Make It Dark - Game Engine, Software Architecture and TDD Prep

Make It Dark - Game Engine, Software Architecture and TDD Prep

As I move forward with the development of Make It Dark, I have reached a crucial point that needs to be addressed before diving into the core coding. This stage is called architectural planning, and it is of utmost importance as it creates a solid blueprint for the game's structure. This guarantees that when I start coding, all the elements will fit together seamlessly to create a polished and cohesive final product.

In this stage, my focus shifts away from the immediate implementation of business logic. Instead, I delve into laying the architectural groundwork to support the game's development. This involves a deep dive into understanding the game's core requirements, envisioning the flow of data between different components, and sketching out a simple yet effective software architecture.

The decision to meticulously plan the architecture before coding isn't just a matter of preference; it's a strategic approach to game development. By defining a clear architectural plan, I aim to ensure that the upcoming development phase is both efficient and organized. This preparation will enable me to tackle the coding phase with clarity, ensuring that each line of code serves a purpose and fits into the larger picture of the game.

Furthermore, this phase is about embracing the complexities of game development and addressing them with thoughtful planning. It's here that I lay the foundations for a game that is not only fun and engaging but also robust and maintainable. The architecture I choose will influence every aspect of the game's development, from how easily new features can be added to how the game's components interact with each other.

Gathering Requirements for Make It Dark

The success of any software project, including game development, hinges on a well-defined set of requirements. Gathering requirements is the process of identifying the functionalities and specifications the final product must fulfil. For Make It Dark, this foundational step ensures that my development efforts align with the game's objectives and the expectations of its players. It involves asking, "What should the game do?" and "How will it deliver a compelling experience?"

Translating the essence of the Lights Out game into actionable and testable user stories guides the development process. This not only clarifies the project's scope but also facilitates communication, providing a common language and a shared vision for what the game aims to achieve.

List of Requirements

The game's requirements, framed as user stories, might include:

  • Enable a Player to Toggle Lights: I want players to select a light on the grid, causing it and adjacent lights to toggle their on/off state.
  • Ensure a Win Condition is Recognizable: I need the game to recognize and respond when all lights on the grid are turned off, indicating a win condition.
  • Allow a Game Reset at Any Time: Players should be able to reset the game to its initial state if they feel stuck or wish to start over.
  • Provide Feedback for Actions: The game must give immediate visual or textual feedback for player actions, such as toggling lights, to confirm the action's effect.
  • Support Variable Grid Sizes: I want the game to support different grid sizes, offering varied levels of difficulty.
  • Maintain a High Performance: The game should perform efficiently, ensuring a smooth experience without noticeable delays in response to player actions.

These stories act as the blueprint for Make It Dark, breaking down the game's development into manageable chunks focused on delivering specific functionalities. They ensure that every feature developed directly contributes to a coherent and engaging game experience. These requirements will guide the development of Make It Dark from concept to a playable reality, ensuring the game meets its intended design goals and resonates with players.

Svelte + Test-Driven Development (TDD)

I've decided to adopt Test-Driven Development (TDD) for developing Make It Dark. TDD is a significant shift from traditional coding practices, focusing on ensuring that the software not only works as intended but is also designed with quality, maintainability, and future scalability in mind. Traditionally, I often follow a "write code first, write tests to validate later" approach.

TDD is based on a simple cycle: Red-Green-Refactor. Initially, I write a test for a new feature or functionality before writing any code, expecting the test to fail (Red phase). This sets a clear goal: make the test pass. Then, I write the minimum amount of code necessary to pass the test (Green phase), focusing solely on functionality. Finally, I refactor this new code, improving its structure and performance without altering its behaviour.

The benefits of adopting TDD in developing Make It Dark are manifold. It reduces bugs in new features, helps in early detection and resolution of issues, and fosters a thoughtful design by forcing me to consider the code's design and interface upfront. The suite of tests acts as a safety net, allowing confident refactoring and improvements to the code, knowing that any changes haven't introduced new bugs.

Moreover, TDD fits perfectly with iterative development. As Make It Dark evolves, the suite of tests ensures that each new addition is intentional and functional, allowing the game to grow while maintaining a solid foundation of tested code. This approach promotes a culture of testing, emphasizing quality and reliability throughout the development process.

In essence, TDD is more than a methodology for writing software; it's a philosophy that prioritizes quality, maintainability, and a deep understanding of the code I write.

From Requirements To Software Architecture

Before diving into Test-Driven Development (TDD) for Make It Dark, it's essential to first outline a clear plan for the game's software architecture. This planning phase is about more than just identifying the components I'll need; it's about understanding how these pieces fit together, how they'll interact, and how data will flow between them. A well-thought-out architecture ensures that when I start implementing features using TDD, each piece of code not only serves a specific purpose but also seamlessly integrates into the larger system.

Planning the Software Architecture

The core of Make It Dark's architecture is the GameEngine, which orchestrates the game's main logic. Surrounding the GameEngine are several key components, each with a distinct responsibility in the game's ecosystem:

  • Grid Manager: Handles the creation and updating of the game's grid, ensuring it accurately reflects the current game state.
  • Light Toggle Strategy: Dictates the behaviour of toggling a light, including which lights are affected by each toggle action. This component allows for creative variations in game mechanics.
  • Win Condition Checker: Evaluates the grid to determine if the player has met the conditions to win the game.

These components are designed to be loosely coupled with the GameEngine through dependency injection. This approach not only facilitates modularity and ease of testing but also allows for flexibility in modifying or extending the game's mechanics.

Understanding Data Flows

The data flow between the GameEngine and its complementary components is a critical aspect of the game's architecture:

  1. At Game Start: The GameEngine initializes the game by instructing the Grid Manager to set up the grid. This setup could be a default configuration or based on difficulty levels.
  2. During Gameplay: When a player toggles a light, the GameEngine passes the action to the Light Toggle Strategy, which calculates the new state of the grid based on the game's rules and returns this updated grid to the GameEngine.
  3. Checking for Win Condition: After each move, the GameEngine consults the Win Condition Checker to see if the player's actions have satisfied the win conditions. This check is crucial for determining the game's progression and eventual conclusion.
  4. Game Reset: If a player chooses to reset the game, the GameEngine triggers the Grid Manager to clear or reinitialize the grid, starting the game afresh.

By carefully planning these interactions and data flows, I can ensure that Make It Dark is built on a solid foundation. This architecture not only supports the current game mechanics but also provides the flexibility to introduce new features or rules in the future.

Scalability with Purpose

Scalability is a key aspect of the game engine. The engine is designed to support future expansions like varying grid sizes and new rules. However, it's important to approach scalability thoughtfully, avoiding speculative generality. This concept warns against over-engineering based on uncertain future needs, which can lead to unnecessary complexity.

In developing Make It Dark, I have a clear vision for its evolution, reducing the risk of speculative generality. This risk is often higher in projects with larger teams and less clear roadmaps. Sandi Metz's insight, "We are bad guessers," is particularly relevant here. It highlights the folly of adding features for anticipated future requirements, which may never materialize. Focusing on present, tangible problems is usually more efficient than planning for an uncertain future.


I've now established a solid groundwork that includes clarifying the game's requirements, mapping out the data flow, and outlining a straightforward software architecture approach. This foundational stage is crucial, setting the stage for the intricate development work that lies ahead.

The process began with me gathering requirements, where I translated the core essence and mechanics of the classic Lights Out game into a collection of actionable and testable user stories. This step ensured that every aspect of the game's development would be guided by clear, defined goals, encompassing everything from basic game interactions to the support for variable grid sizes and the implementation of immediate feedback for player actions.

After identifying the requirements, I moved on to planning the software architecture, prioritizing a design that emphasizes modularity, flexibility, and testability. My discussion around the architecture highlighted my approach to managing key components of the game, such as the grid and game logic. Furthermore, I explored how these components would interact within the game’s ecosystem to ensure a cohesive and engaging gameplay experience.

This methodical approach simplifies the development process and guarantees that each component can be independently developed, tested, and refined before being woven into the larger system. It underscores the importance of thorough planning and the benefits of maintaining a clear architectural vision from the beginning.

Armed with a set of requirements and an architectural plan, I'm ready to dive into TDD and start coding. This upcoming phase will see me translating my user stories into tests and iteratively developing the game's logic to meet these tests, followed by refining the code through refactoring.


Speculative Generality
There’s an unused class, method, field or parameter.