Posted On: 2019-11-11
There are many skills, habits, and processes that were well suited to my previous work (web and tool development) that I have not transitioned quite as smoothly into working as an indie game developer. Today I'd like to write a bit about one that (so far as I am aware) is ordinarily considered a best practice for any programming work, but is particularly difficult to implement in game development: creating software as a series of vertical slices.
A vertical slice in software is a self-contained part of the product, that is completely functional all on its own. The term "vertical" is a reference to how software architecture is frequently laid out visually: each layer of the software (database, front end, etc.) is typically represented as layers stacked on top of each other (kind of like a cake.) A key feature of these layers is that the work required to implement any particular piece of functionality is quite similar, so long as it is in the same layer - for example, getting a recipe from the database is similar to getting a street address from the database - requiring similar skills and programming patterns, while getting a recipe from the database and displaying that recipe to a user requires quite different patterns and skills.
Software architecture is often represented as layers stacked on top of each-other, kind of like a cake.
Historically programming teams have been organized to take advantage of these similarities, with groups or departments dedicated to these "horizontal" layers. One of the issues this presents, however, is that it is very common to have an imbalance of skills or relative difficulty between these layers, which can lead to one or more groups falling behind the rest. Software only functions when all the layers are in place, so having even one layer lagging behind can make it difficult to see what is or isn't working, thereby impairing one's ability to assess quality, gather feedback, or even estimate remaining work.
Along with many other paradigm changes, Agile programming practices encouraged organizing groups around vertical "slices", rather than horizontal ones. If a single group can work effectively in every layer, then an imbalance of work between layers should self-correct, and the group will be "done" only when the feature is available for use and feedback (as compared to one layer being "done" even though it can't be used without the supporting systems in another layer.) While there are pitfalls with this approach (such as difficulty sharing specialist knowledge between groups) under many circumstances switching to vertical slices leads to getting feedback sooner, which makes it easier to react to changes and correct misunderstandings.
Applying the vertical slice approach to my solo game dev work has been much harder than anticipated. Partly, this is due to my inexperience in all the layers (thus I have more areas that I need to learn at once) but I think some unique aspects of game development are also contributing to the difficulty. The first, and potentially biggest of these, is that a game is largely the product of the intersection of disparate systems. Thus, while it is possible to implement one system as a vertical slice, the feedback received with that one slice will not necessarily be relevant once more slices are complete.
As a quick example, imagine a platformer (such as Mario) delivered as vertical slices. The first slice might, perhaps, be the ability to move. Once completed, the second slice could be the jump. Then, the third slice adding one kind of enemy, and the fourth being the interaction between jumping an enemies (landing on top of them "stomps" them.) Taking any particular one of these slices and gathering feedback at that level will yield dramatically different player experiences. Moving without jumping would likely be dull, no matter how good the movement "feels". Adding enemies without a way to fight back against them likely creates long-term sustained tension (dodging them repeatedly) compared to the short bursts of tension that come from fighting back (getting closer to the enemy increases tension, until it is released as the enemy is successfully "stomped").
Since the feedback varies so dramatically depending upon which slice is assessed, it is possible to assess whether the game "works" now (ie. is it fun to play), but not possible to determine whether any particular design will continue to "work" once the next slice is added. Importantly, the design failing might not be the product of the new slice, but rather a product of some detail of a previous slice (for example, the the choice of jump height will impact the experience of jumping over enemies when they are added.) Importantly, since every slice yields different feedback, adjusting based on current feedback might be harmful for future slices (such as modifying the jump to accommodate leaping over enemies could accidentally make it harder to stomp them once that is implemented.) Thus, one of the key benefits of using vertical slices (being able to adjust to feedback early) is threatened by games' nature as being the intersection of systems*.
The second challenge I'll write about is not necessarily unique to games, but it is something that especially impacts them. Many software projects have slow starts: software architecture (like physical architecture) typically requires some kind of foundation to be built before demonstrable value can be created. The amount of foundation required is typically inversely related to the quality/maturity of the frameworks used (for example, a web application built using network sockets requires much more foundation than one built using a relevant framework, like asp.net). This means that, for some domains, it is possible to begin providing value much more quickly than for others.
While I cannot write with authority about the quality of the frameworks available for games, I can articulate that, as a relative newcomer to the domain, many of the assumptions I made about the frameworks were incorrect. Frankly, games contend with many more subdomains (rendering, physics, spacial sound, etc.) than I had anticipated, and many of those that I had anticipated would be "solved" came up short of my expectations* (for example input remapping with support for displaying device-specific glyphs.) As I build out the foundation of my game, I often find the scope increase, as I also have to to include things that I had assumed would be provided by the framework.
Requiring a robust foundation is, in many ways, directly in opposition to vertical slices. If dozens of well-polished systems are required before even the first slice can be created, then that represents a massive engineering obstacle that must be organized and divided up well in advance of providing any value. While some of these are isolated enough that they can be sliced up vertically (ie. a rendering engine) many others are so interconnected with other systems that it's not clear exactly how to evaluate them without a slice of the game proper (ie. a system to save and load world-state.) Unfortunately, in order to build the game, the foundations must be in place, so it's a bit of a "chicken and egg" problem.
Personally, I have not found a suitable solution for these "chicken and egg" foundational systems. For manageably sized systems of this kind, it is possible to include them as a part of the scope of the first user story that requires their presence. Unfortunately, that is often not feasible for systems that are too big for a single story. While working in a team, I was able to somewhat work around this issue, but the approaches used for to do so* are not something I can effectively execute as a solo game dev.
This journey of full-time game development continues to provide many learning opportunities, testing my assumptions and stretching what I know about best practices when executing a project. Hopefully this exploration of one particular aspect of that (vertical slices) has been helpful, or at least interesting.