Strategy and Speed: The Impact of Architecture on Performance
Today, we present the first part of an article prepared in collaboration with our Unity Developer, Vladislav Batyshchikov . In it, he shares his own experience in game development, striving to integrate well-known practices with his personal insights.
Combining various approaches in game development allows developers to merge different aspects of the game and create harmonious code. I may be an expert in a specific area, but I also understand the interplay with other aspects of the game. This flexible approach is particularly valuable in the context of the diversity of game genres on the modern gaming market, especially in hyper-casual games, where they rapidly change and cover new areas.
Before starting the development of any game, there are several key requirements for the project to be successful:
- Time and sequence of events, which form the foundation of the game’s architecture. Everything must happen in the right order and at the right time.
- Compressed development timelines. Programmers should aim for rapid creation and modification of various behaviors in the game, minimizing overlaps and code changes.
- Sequence. After defining all the behaviors of the game characters, their interaction begins. In hyper-casual games, where the emphasis is on simplicity and quick entertainment, interactions should be engaging and easy to understand, while experimenting with character behavior should not cause confusion in the code.
- Game performance. Knowledge of optimization methods determines which games will be successful and achieve millions in sales, and which ones will have low frame rates, dissatisfied users, and high expenses for supporting the project.
What is the architecture of a game project?
We’ve all dealt with such bad code that the best solution was to rewrite it entirely and not revert to the initial state. Some have been lucky and worked with well-designed code that gives the impression of working in a well-equipped game development studio with a team of talented programmers ready to implement any gaming idea. So, what’s the difference?
Game Project Architecture and Its Significance
The architecture of game projects is a critical factor that determines a game’s success. It encompasses not only visual design and level design but also includes the structure and organization of game components.
Well-designed game project architecture ensures optimal use of resources and enhances game performance. It enables developers to efficiently control game objects, animations, physics, and other systems, creating smooth and realistic gameplay interactions. Optimized architecture also reduces delays and improves game responsiveness. Well-thought-out architecture facilitates the development, expansion, and long-term support of a game project.
Unfortunately, achieving the ideal result is not always possible. The notion that you can simply insert new code, represented by modules, so that changes do not create problems in existing code is an illusion. Yet, many companies consider and attempt to achieve such ideal architecture. In the real world, this idea falls apart because even the most perfect code will be meaningless without changes to it.
When stakeholders change their preferences regarding various aspects of game development, aligning it with stakeholder wishes should be a straightforward task. However, in such cases, complexity should increase proportionally to the degree of changes, not their structure. Each new requirement becomes more complex because the structure of the developing game does not match the structure of the requirements. It’s this difference between the degree of changes and the structure that often leads to an increase in the cost of game development.
Functionality or Architecture?
If we were to ask a manager or producer, they’d likely answer that the most important thing is correctly completed work. Developers often agree with this opinion, but an alternative perspective is motivated as follows:
- A developed game that’s working and released but does not allow changes will cease to be useful when requirements change. The game won’t be able to adapt quickly and continue to function as needed by the market, becoming obsolete.
- If a developed game is malfunctioning but is easily subject to changes, it can be adjusted to work correctly and meet changing requirements over time. This ensures its continual usefulness.
Failing to make changes to the project in a timely manner may lead to a point where the cost of changes becomes disproportionately high compared to the benefits gained from the project.
Eisenhower Matrix
Let’s explore the Eisenhower Matrix for prioritizing tasks based on importance and urgency. “I have two kinds of tasks, urgent and important. Urgent tasks are not always the most important, and important tasks are not always urgent.”
The first category is behavior — something urgent but not always important. The second category is architecture — something important but not always urgent. In the game development world, there are tasks that are both important and urgent, as well as tasks that are neither important nor urgent. These tasks can be prioritized as follows:
- Urgent and important tasks: For example, addressing critical errors that hinder proper game functioning or creating necessary functional components.
- Not urgent but important tasks: These tasks may include developing and optimizing game architecture, creating a flexible system capable of supporting future changes and improvements.
- Urgent but not important tasks: For instance, minor fixes to game behavior or visual elements.
- Neither urgent nor important tasks: These might be minor cosmetic changes or additional features that do not impact the core gameplay.
It’s crucial to note that in this list, game architecture holds the top two positions as it’s an important task. Simultaneously, game behavior takes the first and third places.
Often, leaders and developers make the mistake of exaggerating the urgency of unimportant tasks, placing them at the forefront. This leads to undervaluing the importance of game architecture and overemphasizing attention to minor elements. Here, developers must address these issues and consistently underscore the priority of architecture over the urgency of game behavior.
Architecture and Changes
Before you can modify the code to add new functionality, fix a bug, or for any other reason, you must understand how the current code works. While you don’t necessarily need to comprehend the entire program, you should familiarize yourself with all the fragments that the change may affect.
After studying the code, it’s time to start testing it, and an automated testing method is ideal for this purpose. You make small changes to your game and don’t want the next programmer to encounter your mistakes. If the changes are insignificant, a slight reorganization is often required to seamlessly integrate your new code with the rest of the program. If you do everything correctly, the next developer won’t even notice that this portion of the code has been altered, rather than left unchanged.
The Role of Decoupling in Improving Code Quality
Although the architectural design of a program may not seem immediately evident, it profoundly influences the code comprehension phase. Information loading into the brain occurs slowly, and the brain seeks ways to reduce the volume of received data. Much of the design patterns are built on this idea:
- Dependency Injection (DI) is an approach that abstracts object creation, placing it on a separate layer and isolating it from the main application. An example is VContainer
- .Service Locator (SL) creates, stores, and provides any set of dependencies on-demand
- .Component, a fundamental architectural pattern in games, is used for organizing and managing the functionality of game objects.
- Event Queue is used for ordering and processing events in the game. It’s a mechanism that allows adding events to a queue and processing them sequentially in a specific order.
There are numerous definitions of “decoupling,” but the following stand out among them:
- If two parts of code are coupled, understanding one requires understanding the other. By reducing this connection between them, you can study each part independently.
- Changing one part of the code does not affect another.
The primary goal of architectural software design is to minimize the amount of necessary knowledge to start solving a problem. Certainly, later stages are also crucial. Special attention should be given to maintaining order in the code. Situations often arise where many games start with an impressive launch but eventually lose their appeal due to an endless series of minor tweaks and “band-aid fixes” that programmers tirelessly introduce with each release.
Cost
Eliminating dependencies yields a well-architected game project that can significantly enhance code efficiency and maintainability. However, it comes at a price:
- Effort and discipline are required to create and maintain a good architecture as new changes are introduced across various releases.
- Complexity, debugging, increased development and support time will be met when implementing changes.
- Insufficient prediction of future needs and potential over-modularity complicates working with the code.
- Architectural design can distract from the primary goal of software development and lead to a loss of focus.
Delving too deeply into this concept can result in losing control over the code architecture, potentially leading to overly complex interfaces and abstractions. Plugin systems, abundant abstract base classes, numerous virtual methods, and numerous extension points may arise.
When you need to find code performing a specific function, you’ll spend time analyzing it. While you may eventually find what you need, it will consume a considerable amount of time. It’s easy to get lost in the code itself and lose sight of the fact that you are developing a game.
In theory, reducing dependencies means dealing with a smaller volume of code before making changes, but the layers of abstraction can confuse any developer. Code like this discourages people from architectural software design and, in particular, design patterns.
Looking ahead, the forthcoming exploration of “Flexibility vs. Performance: Finding the Sweet Spot in Designing Software Architectures and Crafting Games” promises deeper insights into the intricate dance of crafting software architectures for games. As the digital landscapes of gaming continue to evolve, a well-architected foundation emerges not only as a choice but also as a strategic imperative for sustained success.