Cards Game World - dev log #4
In this dev log:
- my experience “managing” the library, tests, CI, coverage, code analysis, publishing (yes, it’s on npm 🙃, though I don’t recommend playing with it yet)
- automation, testing and more testing
Moving into the cloud…
I’ve received an email from my vhost company that they’ll move my account up one tier and in effect double my invoice. Hmm 😱 By the instinct I searched for alternatives for hosting my games portal. Already had some experience with AWS (lonely S3 buckets) so what the hell, let’s go. If I’m going to seriously consider it my “life’s goal” then I should commit to it as much as I can.
- bought the domain! https://cardgames.world - nothing’s there yet!
- setup servers at AWS using Terraform configuration
- portal automatically deploys to test servers when I push changes to
develop
branch
I always knew bits and pieces of Terraform and AWS and it feels really good to finally try and apply it in the real world. Learnt a lot in the process!
The price though… It was rapidly growing (relative to my tiny budget) and I was afraid it would burn through my savings. Had to close it 👋. And come back to my vhost. I was paying for it to host my and my mom’s blogs so it wouldn’t cost me anything more to just setup a dev server on it… So here it is: https://dev.cardgames.world/, open for public for now, bunch of test rooms and one game. Gotta start somewhere.
Automation
There’s always that thing which keeps an eye on my code and checks everything precisely before it lets my code get deployed. And I’m thankful for that.
I started with CircleCI but have some additional workflows on GitHub. I like both, they do have some differences, but most importantly - you can use both for free 🤓
For the @cardsgame
libraries:
- install, build and lint whole repo
- run unit tests and remember coverage reports
- push these reports to coveralls.io
- push the code to sonarcloud for code quality analysis
- if all above is good, and it was a commit tagged with some version
npm publish
🥳- and finally publish docs
Some tasks can event be performed in parallel!
The whole CircleCI config is available on Github if you wish to gain some inspiration: /.circleci/config.yml
For the Card Games World portal:
- try installing, building, unit test and check for lints
- run e2e tests with Cypress,
- and finally deploy
to THE CLOUD, to EC2 instance via AWS CodeDeployto my vHost dev environment for now
As I mentioned, I did managed to run the portal in AWS (it took me 2 weeks to get right), buut that’s not happening for now.
side node: CircleCI now also notifies me of the results on my Discord channel. Even SonarCloud started reporting via Github’s comments 😄 Everything in one place!
Coveralls
Not much to say, it just works™ and my code coverage percentage can be nicely seen on a timeline!
SonarCloud
At first I couldn’t set it up properly. Sonar would report that TEST files were not “tested”, which in turn lowered my test coverage percentage 🤨.
I managed to fix it up and it started pointing out some “code smells” and possible bugs. Most of them were:
- code duplication - great place to start! De-duplicate and put things in one function
Math.random()
is a weak pseudo random generator for cryptography! Understood - won’t be using it for “securing” things anyway.- remove unused imports - I’ve got so many files right now I didn’t spot that one little import, thanks!
Next kind of issues were ”property accessor not being used” (or something like that). Here’s an example:
getConditions: (con) => {
// Both lines are an issue
con().is.playersTurn; // ensure its current players turn
con().is.owner; // ensure player interacts with their own cards
// -- or
con().is.not.playersTurn;
con().is.not.owner;
};
For you, a reader who’s not familiar with my library, that would in fact look like I’m accessing some property and not using it anywhere. That’s exactly what SonarCloud saw and reported. But both props are in fact a getter function with side effect. Their purpose was to throw an error, when game state conditions fail (these errors are safely caught at the scope above no worries 👌).
At first I was stubborn with this solution. I thought:
I’ll document it, have it in types definition and people will know how to use it!
So I just kept marking as “false positive - caused by algorithm limitations”. Yeah, it’s not my fault SonarCloud couldn’t guess the usage of that getter…
I’ve concluded that it actually is an issue and I should change it. If it’s unintuitive I should not promote such code patterns just for the flex. Code should be as clear and easy to understand as possible.
So now, all “assertion functions” are just functions instead of magic/confusing getters:
getConditions: (con) => {
con().itsPlayersTurn();
con().playerOwnsThisEntity();
// Negating it now sounds weird, I know D:
con().not.itsPlayersTurn();
con().not.playerOwnsThisEntity();
};
Last kind of reported issue is understandable, SonarCloud was probably not aware of optional chaining (at the time I last tested), so the line below would get reported as “Expected an assignment or function call and instead saw an expression.”.
state?._registerEntity(this);
Closing thoughts
This is it for now. I might drop the “dev log #number” format, as I’ve done so much more things around this whole project, and it would be silly to not include the important bits in the title.