DEV Community

Cover image for 10x Sprint Master: a technical and social experiment
Eduardo Pinho
Eduardo Pinho

Posted on • Edited on

10x Sprint Master: a technical and social experiment

I recently wrote a game for the GitHub GameOff jam, which has been a fairly common practice of mine for a while. 10x Sprint Master is about software development, team coordination, quality assurance, bug fixing, workplaces, and taking breaks for coffee every once in a while. In other words, this game is about work. The tech work that so many developers out there have, except that it's intended to be fun.

The next section of this post is a description of the game. Afterwards, there will be a more technical section, in which I will cover the technologies that were used, as well as personal notes and expectations about their use. Finally, the third section makes an introspection into the social aspects that give the game a personality of its own.

Description

The game puts You in the shoes of a development lead engineer, who has just arrived into a fictional company, and will soon become responsible for creating tasks to perform, specifying what each task entails, and assigning them to members of the team, while managing the life cycle of each task.

You don't have a name (the caption "You" appears below your avatar), but you are given the opportunity to name the product or project to whatever you want (even though the company is nameless). And oddly enough, all your team members have actual names.

The entirety of the game takes place in front of a project workboard, consisting of 5 columns, each representing a stage:

  • The Backlog stage is where new tickets arrive.
  • The Sprint Candidate stage turns stub tickets into well specified tasks.
  • The In Progress stage is where the actual coding takes place to fulfill the task's acceptance criteria.
  • The Under Review stage is where tasks are checked for bugs. If bugs are found, moving them back to In Progress allows you to fix them.
  • Once ready to go upstream, tasks are moved into the Done stage, and can no longer be interacted with.

As you start the game, and if you kept the Onboarding option checked, you will meet with the former lead engineer, who will explain you how to do things. But that mentor will also leave you at the end of the month, and so you will be forced to inherit the entire knowledge and workload during that time! To the player though, it amounts to knowing how to drag and drop tickets around with the mouse.

In-game screenshot: Month 3, two developers

You start the game severely understaffed: only you as the developer. A few months in and new hires arrive. However, they will not have the same experience as you, so they will work slower until they get better over time. And speaking of time, some tasks have a deadline, and sometimes you are given some final hour feature requests.

Every while that a developer writes code under a task, they may be introducing bugs. 🐛 The review stage is the place where they are hopefully found. 👀 ...that is, before it is too late and they are merged. Irrespective of that, each contribution brought upstream increases the complexity of the software, which can be mitigated with chore tasks. As time passes, the tasks to fulfill become more and more demanding.

Occasionally, you will receive random messages from your peers for the full workplace experience. They will complain during their coffee breaks ☕ about the excessive number of meetings. You will receive reminders to pick the toppings for your pizza lunch. 🍕 You may also be asked to help the DevOps team, which is almost always in trouble.

And yet, the game actually does not mention how much these developers get paid. There is no salary negotiation, no distribution of dividends, not even a worthy mention of how well received your product is.

What exactly drives the player to continue going, then? Well, there is a score. Merge tasks, and it goes up. Mistreat your software with too many bugs and technical debt, and it will slowly linger over time. Make it too difficult to work on your projects, and your team members will give up and leave, only making things worse. Ultimately, optimizing for score requires you to strike a balance between feature delivery, bug fixing, and technical debt mitigation.

Do this well enough and you will receive a special call from the CEO! Well, this might not actually be possible though. Please let me know if you ever manage to achieve this.

A technical experiment

Primary tooling

I decided to write this game in HTML, CSS, and... that's right, Rust via WebAssembly.

It was never a matter of whether these were the right tools for the job. It was about gaining experience in a field which I only had minimal grasp of, and about understanding how far one could go in frontend development for the Web using Rust, a programming language which I enjoy and am already well fared in outside web front-end development.

In the process, I picked Yew as the Web framework. There wasn't too much thought put on this decision, but I felt that it was the most mature Rust solution for dynamic web applications. Trunk was used for building the project, which is apparently a common choice here. It is far from being as complete as Webpack or Parcel, but it did the job as intended:

  • trunk serve would continuously build and refresh open pages on any source changes;
  • trunk build would do the process once.

Combine that with additional options and Cargo tweaks, and that would give me all resources, optimized, hashed and ready to be published.

There was only one relevant tweak I had to make in the distributed index HTML file in order to make it work on itch.io: the paths to the various assets had to be modified to be relative paths instead of absolute paths. This is because itch.io provides the games' assets in a cross origin which will not sit in the root path.

Graphics and design

I have also been taking Josh Comeau's CSS for JavaScript developers course, and I took this jam as an opportunity to apply my new skills. Even though I have only completed the first few modules, it has so far enabled me to have a much better grasp of CSS, instead of just blindly messing around with properties until I got what I wanted. If you are interested in knowing how to write modern CSS, there is no other course I could recommend but this one.

As such, the game's design was primarily driven by CSS, with some emojis to serve as memorable icons. Even the characters and the cute little bug presented in the tickets were made with a bunch of styled divs. Keeping that part of the application away from Rust felt ideal, so as to reduce DOM manipulations to the minimum necessary. Even the animations in the onboarding phase demonstrating how to move tasks around were completely devoid of JavaScript or WebAssembly to function. I liked them pretty much.

In-game screenshot depicting one of the messages during the on-boarding phase.

There's even an easter egg: stay in the main menu for a while to see something cute. All in pure CSS. 😬

I added PostCSS so that I could use @import statements and incorporate automatic prefixing. One of the minor nuisances that I could not resolve was to join PostCSS and Trunk together when serving the application locally. I ended up creating an npm project with multiple scripts to run all the necessary steps, and I would just run a CSS watcher alongside trunk serve in another terminal.

Using Rust

But to speak of nicer things now. Thanks to the use of Rust, working on certain features was a breeze.

Game state

The game's state was serialised and deserialised back using serde, achieved with little more than a few automatically derived trait implementations. With the use of a textual representation, it was possible to rely on the standard Web local storage to save the game. It wouldn't always work when hosted on itch.io, unfortunately. Browsers are finicky when you depend on storage for a cross-origin resource, and might block it completely. I had to tell players to disable their browser shields in order to save their progress.

There were a few other pieces of information which were passed around in a serialised form through the Drag and Drop API. This in particular felt like a great achievement, as I had to include a custom helper abstraction for access to data transfer properties. This is what made dragging and dropping work. Alas, this API would have required a lot of work in order to support touch events and other forms of feedback that I was hoping to obtain, but were not possible through data transfer alone.
The constraints caused by this were:

  • The game does not work on mobile devices, although this support would have been wonderful to have.
  • Feedback about an operation would only appear after the fact: instead of the workboard stage column appearing with a different style when hovering a task over it, I added a message in red at the top of the workboard whenever the player tried to make an invalid move for a task , such as from Backlog directly to Done.

Random stuff

Random events of various sorts were triggered with the help of rand. I found rand_pcg to be nice and fast for the purpose. The ugly story here is that the odds of something happening at a game update tick (be it whether a bug is introduced, a new task should appear, etc.) was achieved with a mishmash of formulae combining a variety of in-game parameters in a very creative way. This came with the problem that they were quite hard to tune, 🔧 which in a way contributed to the game's notably high difficulty. Note to self: create better abstractions for random events next time.

With these events and other game entities generated, the elegance of Rust enabled me to manipulate the game's task in ways which I was already well versed in. Iterators were employed throughout when transforming tasks and updating state based on them.

Yew

Last but definitely not least, I will talk about Yew.

  • It required me to perform many more .clone()s than the ones I would usually do. This is mostly because component properties had to be owned by each instantiation, although I did not get into whether they this was always necessary. In any case, there were a significant bunch of clones.
  • The macro based syntax for declaring virtual DOM nodes did the job, but it was quite verbose and a bit tricky to get the hang of. It was annoying that all hardcoded text strings inside had to be enclosed in quotes as well as an expression block (e.g. <div>{"Something"}<\div>), although this may have to do with a limitation of the macro system. As part of a macro, syntax highlighting was constantly broken.
  • It further reinforced my idea that working with callbacks in Rust is a mess. It is already a paradigm which I strive to avoid, but there is no way to avoid it here. Closures had to capture context in a special way, and interfacing with the JavaScript environment required a bunch of conversions to make things work. There were helper methods to create callbacks interfacing with Yew, but it was still a bit surprising when the program failed to compile once I tried to use some component state without cloning it beforehand. That pattern became clearer, but it still put me to the test of how much I knew about ownership, borrowing, and non-lexical lifetimes.
  • It was not always clear how one is expected to manage the game's state and trigger changes from user interactions down the tree of elements. I ended up implementing a global event dispatcher that the main game component would listen and handle immediately (e.g. for pop-up messages) or pass on to a game update routine. It was a weird piece, and the primary game component was much more complex than the other ones because of it, but it did just what I was looking for.
  • It was fast enough. It would have been nice for me to say that it was blazing fast, but I don't have a point of comparison. That would require me to rewrite the whole thing in JavaScript. 🤢 Still, even though the DOM had to be updated around once every 50 ms, this was far from becoming a problem. Most updates would take less than 3 ms each (compiled in release mode) in my personal laptop, 9 ms in debug mode worst case.

The source code is available on GitHub, as is typical in GitHub GameOff. Enjoy.

A social experiment

The idea of making such a nerdy strategy game that puts you in the role of a software engineer wasn't very new. I had kept a similar idea for the right time to work on it, but 10x Sprint Master, albeit just as nerdy an idea as I could come up with, was on a whole different subject: treating the project workboard as the center of all attention in software engineering.

It is worth noting that this game was never meant to make an accurate portrayal of any well known agile methodology, such as Scrum. There may indeed be similarities, but ultimately, this is not Scrum, and I definitely wouldn't depict this game as educational. For all intents and purposes, it was just some method what the fictional company decided to stick to.

Most importantly, this game subjects the player to the encumbering of technical debt in a way which could never happen in real life. Time goes fast, and once you reach unbearable levels of complexity, you are submerged in a pool of deadlines impossible to meet. There is no actual losing condition, but I find it perfectly normal for anyone to give up and exit the game at that point, thus emulating a losing condition all the same.

It is a bit brutal, even if not on purpose. All with the primary goal of accumulating points which don't translate to promotions, raises, or any other kind of advancement or compensation. In retrospective, this game feels like a prank on myself. A self satire of engineering endeavours under the narrow mindset of testing a software project as the means to further work on the same project, where the goal is to optimize for more features, more quality, and less technical debt, all under the guise of a seemingly familiar daily routine.

Maybe next time I'll just build a platformer or something. 😐


You can play 10x Sprint Master on a modern web browser here.

Top comments (0)