How I improved my Javascript and Typescript skills by building a Discord Bot
Tags: javascript, typescript, discord, bot
Published: 2021-10-05 21:12:52

Hey there!
I've been having fun developing a Discord bot, and today I'll share how I used it to improve my Javascript and Typescript skills.

{% github https://github.com/Markkop/corvo-astral/ %}

## 🤖 About the Bot

Corvo Astral is an [open-source](https://github.com/Markkop/corvo-astral) Discord Bot that provides information about an MMORPG game called [Wakfu](https://www.wakfu.com/), made by Ankama. It's being used in over 230 servers, and it's also featured in [top.gg bot listing](https://top.gg/bot/750529201161109507).  
It started with a simple command that did some calculation given some character attributes, but as soon as I saw potential for cool stuff to do I went all in.  

![Calc command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7fmn25jvs02833azl2vf.png)
 

## 💻 Initial Development

The reason I used Javascript and NodeJS was the most obvious one: it was the only programming language I really knew about that time. 

Also, the [DiscordJS](https://discord.js.org/#/) library have a pretty neat documentation, so that really helped.

I started by google searching all the way up to make the bot working, as any developer would do when starting a project for the first time. 

Having it responding to commands was pretty easy, and adapting the code to accept multiple commands without `if/else` and `switch` statements was not that hard too.  

{% gist https://gist.github.com/Markkop/f4eb558faebece634bc384c66ae5bb9f %}

After implementing the `.calc` command I got hyped to add the `.alma` command, which stands for [Almanax](https://wakfu.fandom.com/wiki/Almanax_Quests), the name for the daily bonus that can be obtained in the game.  
While the current bonus cannot be obtained using an external API, it can be guessed using date manipulation.  
I was very happy to come up with this solution. And I even used in my [guild's website](https://github.com/Markkop/corvos-de-efrim-website/blob/master/src/components/molecules/Almanax.js).

## 🛠️ Testing

By the way, I was looking to improve my testing skills, so most of the code - including my precious daily bonus prediction command - was implemented using **Test Driven Development** (TDD). It ended up being great for maintenance and future upgrades I made in the bot.

## 📥 Importing Data

My next and biggest command implemented was `.equip`. While creating the logic for finding the matching equipment based on its name and rarity was not that hard, the real work lied into obtaining the equipment data from the game.

The good news was that Wakfu had a [Content Delivery Network (CDN)](https://www.wakfu.com/en/forum/332-development/236779-json-data) that I could use. 

![Wakfu JSON Data Forum Post](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gqk9znfd062lg0nhvdnj.png)
 
The bad news is that it comes with lots of split data, so I would have to assemble all the information I'd get from there.

This time I went in a Go Horse mode and coded all my way up into having readable content that the bot could provide to the user. 

Surely enough, I've regretted not making tests or even a better code as soon as the game launched a new version with newer items. 

The bot would be outdated for several months then.

Here's an article I wrote about interpreting some Wakfu data:

{% link https://dev.to/heymarkkop/decoding-wakfu-s-action-effects-with-javascript-1nm2 %}


## 💡 Side note: semantic commit names are worth

I mean, to write this post, I'm basically looking in the project's [commit history](https://github.com/Markkop/corvo-astral/commits/master) to remember the order I've built the project and its difficulties. 

100% worth

## 💾 Importing extra data

While the CDN had almost all the data I needed, it didn't had some really useful information like equipment states (their special effects description) and equip conditions.  

The way I've found to obtain them was getting all the equipment from a fan site that had a Builder tool and enrich the data. 

![Method Builder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ladzwxwwh9f8oddv4kzi.png)
 

Almost a year later, this webpage shut down (not my fault, I swear!), and my data was even more outdated.

## 🕸️ Web Page Scrapping

Another way I found to get cool data was scrapping the game's encyclopedia webpage. The user could request the drop information for a given equipment, [monsters strengths, weaknesses and drop table](https://user-images.githubusercontent.com/16388408/101432541-ce9e1700-38e7-11eb-8214-3a048596d944.gif) or even get some [trivia facts for the current ingame date](https://camo.githubusercontent.com/19a3f31b728cca9d6c0bb0d32df8d79ef406ff9bdf5f6f4e0d26613d65ed05c0/68747470733a2f2f692e696d6775722e636f6d2f42564f714532702e676966).

Unfortunately I had to remove these features after the company implemented a website protection service against DDoS attack and - in my case - web scrapping.  

The web scrapper implementation in the bot was not totally useless thought. I made it so whenever someone would share a character build link in a channel, the bot would scrap the page, sum the total equipment stats, take a screenshot and reply the user with a preview, so people didn't need to actually access the website to check the build.

![Build Preview demo](https://user-images.githubusercontent.com/16388408/102099728-5bc0fe80-3e07-11eb-86a4-e61081ee314c.gif)

## 🌟 Even more features

I couldn't stop there. I implemented other cool commands, such as finding sublimations (equipment enchantments) according to their color slots. Not only that, but I even did a Party Finder system that allows users to post a party listing, and others were able to join it or leave it simply by reacting to it.

![Party Listing demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p125xudpi9x2knjr3thi.png)

Also, as I wanted to reach more people, I've added internationalization in the project, allowing commands to be used and translated in all four languages supported by the game: English, French, Spanish and Portuguese.

## ⚙️ It's Refactor time: OOP and Typescript

As I was creating new commands, I felt that I could reuse and abstract a lot of code. Furthermore, I was studying **Object-Oriented Paradigm** concepts and **Typescript** by that time, so it was the perfect opportunity to practice both.

On top of that, I tried to follow some **SOLID** principles and **Design Patterns**, but sometimes I felt that they would increase a lot the code complexity. 
And some of them are kinda incompatible. 
Using the Singleton pattern to let a single class instance manage each server's config was great, but it broke the Open/Closed principle.

That shows how practicing OOP/SOLID/Design Patterns in this project was awesome: I was able to understand, in a real project, why these programming references are great to know, but aren't always the best solution.

And by using Typescript I barely had bugs in production. I still can remember implementing a new command before the TS migration and finding `undefined` behavior as errors in Heroku's logs.

Surely having those test cases implemented since the start helped a lot as well.

[![Refactoring Guru](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2tj64naeuaybnpbnanid.png)](https://refactoring.guru/design-patterns/singleton/typescript/example#example-0)
 

## ⚙️ Refactoring tests

As I said earlier, the reason I coded lots of tests since the start of the project was also because I wanted to practice TDD and tests frameworks.

However, since I've changed a lot the source code with OOP classes and Typescript, I had to adapt those as well.

The biggest challenge was mocking the Discord dependency entirely. 

While in the previous approach I could just mock and spy the `.send` method with an object and some other methods, this time TS would complain a lot about missing properties.

{% gist https://gist.github.com/Markkop/97ebdb7adf9b2852f91e574a31a8d3b9 %}

Pretty ugly, right? (but hey, it worked for its purposes)

After lots of searching, I've found a pretty cool mock that I was able to adapt. Here's the current code: [tests/mockDiscord.ts](https://github.com/Markkop/corvo-astral/blob/master/tests/mockDiscord.ts)

Along with this new approach I had the ability to test some features that I had no idea how I would do previously, like message reactions (and therefore the Party System itself)

## 🔮 The future

Now you can get the idea on how big and cool this project is (specially if you play this MMORPG).

There are still some things I'd like to change and implement, such as using slash Discord commands, adding more translations, allowing users to add custom extra equipment information and more.

However, there's only one thing that can kill this bot: money.

Since the start, I've been paying its Heroku hosting costs with Github Education credits, and they should last for a few more month
 s, however once they vanish I will not be able to keep it running anymore.

![Untitled-1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6ln9hpj1cmqablsafia.png)

Seven dollars per month it's not that much, but our currency here in Brazil isn't in its best situation and anything evaluated in dollars are 6 times more expensive for us.

That's an extra reason to refactor this project. By making it easier to maintain, I could update its database and ask for donations.

If you would like to help a fellow developer or if you're a Corvo Astral user, please consider contributing:

https://www.buymeacoffee.com/markkop

Thanks for reading!