Implementation of Minesweeper game. Try it out here.
2. Architecture and Dev Journey
This game is part of a technical evaluation. Minesweeper is a single-player puzzle video game. The objective of the game is to clear a rectangular board containing hidden "mines" or bombs without detonating any of them, with help from clues about the number of neighboring mines in each field.
This project has three main modules:
- API: A Restful API that provides access to create and play Minesweeper matches using different users
- APP: A Single Page Application that implements a playable Minesweeper Board, and options to login and load previous matches
- SDK: A library to handle API integration between APP and API. SDK is published on NPM here
For the API, I originally I decided to gor for a 3 layer architecture, where:
-
An applicatio layer takes responsibility for validating input data, and routing through the available services.
-
The service layer provides a set of services that models the operations and flows of the domain.
-
The manager layer where the low level data access is implemented.
For the evaluation time restrictions, I decided to merge both the service and manager, so the transformation logic from the database responses to the service models are in the same place.
A decision -a bad one- that I made early on was not to use any form of ORM to make it a more interesting implementation. Turned out that consumed a bit more time that expected, and made the implementation more complex as well.
To interact with the Minesweeper matches, I decided to use a Command like pattern approach: Match Service is capable of receive Match Commands, and those commands execute operations over a Match, updating its internal state, and potentially the Match state (WON, LOST, IN PROGRESS, etc). This was definitely a good idea, and later on made the integration with the APP simpler and intuitive.
One last comment about the API is the LRU. I was not expecting performance issues with MongoDB, but turns out that the free tier of Atlas was kind of warming up for each query. In order to mitigate that, I implemented an In Memory cache that saves the state of the Match there, and prevents any save unless the user explicitly saves from the UI. In a more realistic scenario, I've used a queue with persistent messages for the match commands, or a Redis.
Regarding the APP, I decided to go with React and Create-React-App, which are the technologies I feel more comfortable with (Probably theres better options for games). Pretty much the only add on to the standard, scaffolded Create React App is the addition of React Router to handle routing.
Theres one thing that are Im not happy with the APP implementation, and that is that I used different models for the Cells representation coming from the API, and the internal Cell model used on the UI. That generated additional transformations on the client side. If I were used the same model on both, the code implementation would have been a bit more cleaner. Also, the Game component is a bit complex. With more time, Ive refactored it a bit and extract some potiential components from it.
Walkthrough Video with Demo:
-
Verify that you have NodeJS 10+, yarn and a local instance of MongoDB installed on your computer.
-
Run following command to install APP dependencies
cd app && yarn
-
Run following command to install API dependencies
cd api && yarn
-
Setup env file:
cp .env.example .env
and change MONGODB_CONNECTION_STRING property for the Mongo Conneection String of your local instance, and MONGODB_DB_NAME to the name of the database.
-
Start API running:
cd api yarn debug-build yarn start
-
Start APP running:
cd app yarn start
-
Execute Unit Tests with:
cd api yarn start
Originally my idea was to create a Swagger doc, but due to time restrictions, I've decided to switch for a Postman collection. The collection is in the root folder of this project. To use it, simply download Postman and import the file.
Date | Tasks | Time |
---|---|---|
06/02/20 | Started working on project! Invested time reading the requisites; about Minesweeper rules, variations and mathematical models around it. | ~1.5 hs |
Defined an initial approach to the solution: project will contain three components: a RESTful API, an API SDK (client) and a web app. | ~1.5 hs | |
Defined a tech stack: API will use Typescript so I can take advantage of the stronger type system, Express as web framework, Winston for logging, React for the app, and create-react-app | ||
to scafold it. | ~0.5 hs | |
Created a public git repo with the initial structure of the project, plus setup of gitignore, tsconfig, webpack file, etc. | ~2 hs | |
06/03/20 | Setup of Digital Ocean Droplet where API and APP will be deployed. | ~0.5 hs |
Completed an initial end to end integration between a test service on the API, and MongoDB. | ~1 hs | |
Implemented a simple MongoDB native driver wrapper to execute queries to the database. | ~1.5 hs | |
Setup of Mongo cloud instance on Mongo Atlas, and integration with the API. | ~1.5 hs | |
Setup and implementation of unit tests for models, utils and services | ~2 hs | |
06/06/20 | Made a first code refactor to improve quality of the implementation, particularly on the commons / utils module, and he services | ~2 hs |
Integrated an LRU cache on the Match service | ~2 hs | |
Implementation of the Command pattern inspired solution to control the execution flow of the game through the Match service | ~2 hs | |
Initial setup of Swagger | ~0.5 hs | |
06/07/20 | Implemented the board interations and algorithms of initialization, and other algorithms required through the game, particularly Floo Fill for adjacent cells without bombs. | ~1.5 hs |
Implemented first APP version using React, added React Router to handle the different scenes of the game, setup integration with API more in detail, tested login API | ~4 hs | |
Implemented and Integrated a module to send commands to the API to play the game | ~2 hs | |
Implemented remainig views of the APP, several bug fixes during test. | ~3 hs | |
Updated documents and styles (jsdocs, tests, code formatting) | ~0.5 hs | |
06/09/20 | Wrapping up implementation, fixed several bugs on inputs | ~3 hs |
Added validations | ~1 hs | |
Created SDK. | ~2 hs | |
Updated README, deploy latest version of the APP and API to server, minor improvements and created issues to track existing problems | ~3 hs |