For two years, I've been a community member of and contributor to The Odin Project, and in my time there I have grown from a help-seeker to primarily a help-provider. TOP's curriculum features many opportunities to build games, from simple ones like Rock Paper Scissors and Tic Tac Toe, to more complex ones such as Chess and Battleship.

As a Javascript developer, much of my learning happened in the browser environment where access to markup and styling is conveniently close at hand. As wonderful as this is for the process of game creation, I have often witnessed the tendency for inexperienced learners to fall into the anti-pattern of interacting with the DOM too freely within their game logic.

Before we begin, I want to emphasize two things:

Modern applications are built in various ways depending on scale, scope, requirements, technological restrictions, etc... This article is not intended to teach about application design, nor to provide a one-size-fits-all methodology to building any web app. Its intent is to teach good practices for separating state logic from the UI controls within the context of vanilla JS.

This is not a code-along. I will be creating a game as an example of how to implement this separation of concerns, but it is not expected for you to build it along with me. However, for further learning, I will include a few practice assignments to help apply the concepts learned here that you can do by forking the Replit.

Imagine the outside
Pretend for a moment that building a game application is something like building a house. Imagine your dream house, and what it looks like in its final form. You're probably imagining all the elements of a house that are supposed to be seen from the outside and enjoyed aesthetically: the outside of the house, painted to your liking, decorations, the front yard, a charming front door. As you move inside, each room looks like it came straight from HGTV. Brand new appliances, furniture, etc...

But what about the structural elements of the house? Of course we appreciate those things too, but we don't often think about them because their implementation is hidden from our view in the final product. However, behind each wall in our house we can trust there is a sturdy frame. Above the ceiling, and below the floors, we trust there are joists and beams designed to keep the house standing. Underneath the house, we put all our faith in the foundation, which is responsible for holding everything else in place. Behind each exterior element, there is an interior support structure. In the same way, our application's user interface should be a visual representation of underlying application logic. In other words, behind everything that makes our game look and feel nice, there should be solid, foundational code.

Build from the inside
It's easy to focus on the visual and interactable elements of a project, just like it's easy to imagine how a house will look from the outside when we dream of building one. But just like a builder would first consider the structural design and blueprints of a house before beginning to imagine walls, doors, and windows, let's attempt to think through how our application is going to function at its core before implementing details in the user interface.

A builder would never construct a wall that had no frame to support it. It is not the responsibility of drywall or plaster to support the weight of a house, nor, by itself, provide a sturdy barrier between rooms. Similarly, our DOM elements and queries should not be responsible for storing or handling the implementation details of how our application works. That is not their responsibility, nor what they were designed to do. They shouldn't be concerned with storing details on the state of our game, nor handling the logic our game requires to function correctly. Instead, the DOM should be responsible for reading and displaying the application state to the user and providing an easy-to-use gateway to interact with the methods it needs to.

For example, if I am making a game, my UI should have access to a method it needs to use in order to play a round. This method should be simple to call and as restrictive as possible (meaning, it should not need to provide a multitude of arguments to do something). Conversely, the DOM probably doesn't need access to a way of changing which player's turn it is. Instead, it should be able to read whose turn it is as it changes after every round. This is an important distinction, and one I hope to further illustrate later.


Eu gostaria de entender essa parte: "Conversely, the DOM probably doesn't need access to a way of changing which player's turn it is. Instead, it should be able to read whose turn it is as it changes after every round. This is an important distinction, and one I hope to further illustrate later.". Se póssível com exemplo, por favor.

Estou aprendendo sobre Module Pattern (Não com classe, mas sim com IIFE + Factory Functions)