3/6/2022
What's in an application
This is something I really like talking about with my students.
It can also be a frustrating experience for me, because I know these high level concepts are counterintuitive and difficult to fully digest.
The general ability to take a complicated topic and distill it into a simple and deliverable chunk of information is already a challenge.
Couple that with the difficulty of most listeners and readers to expand that idea back out into usable information as part of their mindset...it can be disheartening.
Still, this type of distillation is the greatest bang for your buck value that I can give you for your reading time.
Information Systems
All applications are based on information. There is some input of information, there is some process that transforms that information into viewable content.
That's really all it boils down to.
Data -> Process -> View
Examples
Here are a couple quick examples to help get the idea across. Let's say we have an array that represents the state of our tic tac toe board.
let board = [
"", "", "",
"", "", "",
"", "", "",
];
// Or with some values after a few turns:
let board = [
"X", "O", "",
"X", "", "",
"", "", "O",
];
This array is that data/state of our application. Now we need
some process
that can transform this into viewable information.
There are infinitely many processes we can write to transform this data into infinitely many views. Let's see a couple of interesting options.
Let's say an engineer wants to view the data to understand the
current state. The dreaded console.log
statement:
console.log(board);
This is a process that emits a view! It takes in some data, does something with that data, and then spits out something for us to see! In this case the view is being generated in the console for the programmer to see.
Data -> Process -> View Array -> console.log -> Data viewable in console
Now let's see how we might transform this data into a string of HTML.
function generateCellHtml(value) {
return `<div class="cell">${value}</div>`;
}
const cellHtml = board.map(generateCellHtml);
const htmlString = `<div class="board">${cellHtml}</div>`;
document.body.innerHTML = htmlString;
Data -> Process -> View Game board array -> html generation -> viewable in browser
There's some nuance missing in the above example. If I actually
wanted to do this I would probably also include some logic to
add .row
s for each "row" in the game board.
Note: What's crazy is you can view your own source code this way!
Data -> Process -> View
Thoughts -> Typing in text editor -> Source Code
Your source code is a view into your thoughts about the program!
Take this a step further and you can realize that using a different set of tools or programming language is really just switching out the P
bit in our D -> P -> V analogy
State
State is the one of the most crucial parts of an application. Getting it wrong can make your life many times harder than it needs to be.
Getting it right will not only make maintaining your application easier, it will enable you to build features that would other be challenging.
One of the early goals of the Tic Tac Toe project is having students make a bunch of mistakes with how they think about and store the state in their application. In fact I specifically avoid mentioning the word state when introducing them to the web platform and getting them started on the project.
It's good for students to first face the issues of having mangled state so that they can see how much easier life would have been if they had first been disciplined about their state.
The naive approach to getting tic tac toe up and running is to just mutate the actual HTML and let that act as both your view AND your state:
function getCells() {
return document.querySelectorAll('.cell');
}
function cellOnClick(event) {
// Hardcode X for now
event.target.innerHTML = 'X';
}
window.onload = function() {
const cells = getCells();
for (const cell of cells) {
cell.addEventListener('click', cellOnClick);
}
}
The above will get you to the point where you are setting cells to X on click. Not bad, but how can we go about checking for a winner now?
Well, the only information we have right now is the actual
value of the innerHTML
property of each cell...yikes
const cells = getCells();
const board = cells.map(cell => cell.innerHTML);
// board will be an array of 9 elements, like:
// [ "", "X", "", "O", "", "O", "", "", "" ]
So you have to look to the HTML to be your state. Technically you can make this work, but it has a couple of nasty properties.
By coupling
your state to your view you lose a lot of control.
How would you go about writing a test to cover your win condition
logic? I can actually think of a way to do this, but rather than
solve that problem, let's see if we can decouple our state from
our view instead.
State -> Process -> View
We have this little D/S -> P -> V analogy, let's keep going with that. We already discussed what the D/S part of this might look like, but let's recap really quick.
That data for our tic tac toe game is just the board itself.
let board = [
"", "", "",
"", "", "",
"", "", "",
];
Great. Now what about the process
bit? Well, we could follow
the earlier example and actually build a string of HTML. That's
honestly trash and I would never want to hand roll a bunch of
HTML generation code. Just use a component framework.
For now I think a good middle ground is to put the cells in the HTML and just update their values based on the state. Like this:
function renderBoard(board) {
const cells = getCells();
for (const [cell, index] of cells) {
// This is the fun bit
cell.innerHTML = board[index];
}
}
Above we are mapping
that values in our board array to
the cells based on the index of the cell. More importantly,
by encapsulating that logic in a function that depends
only on the board, we can easily replace it with something more
complicated later.
Conclusion
Hopefully you're starting to see how we can pull the state out of our HTML and take back control. In the next article I'll take you to the finish line and show you exactly how I would structure the state for my version.
I'll include a github link at the end so you can take a look at all my code.
Ask me questions on twitter or email me at ty@tytr.dev