Code Style Changes, or, why I've rewritten the bot three times.

The year is 2016 and I'm still in secondary school, studying away and finishing assignments in some classes faster than everyone else and doing everything other than what I'm supposed to be doing for others.

Now, around this time I had a group of friends I'd met online that I'd be talking to during classes as you do when you're not paying attention to the teacher at all, but those relations had been increasingly fading away with time as we all grew up and away from eachother.

"Why is this important?", you might be asking, and it's because one of my friends in that group that I even started this bot in the first place, or well, got on Discord.

See, I was really, really close with this person and I wanted to have closer contact with them as Skype just wasn't cutting it. So I asked them about any other services they were using, and they told me about Discord, and the rest is history.

...

Well, not really.

During the midst of this friendship group growing apart, I more or less lost contact with everyone except this one person, until one day when they vanished.

I quickly sent a message to them on all the platforms we've used, Skype, Twitter, Discord, you name it.

No response.

"Maybe they're busy?", I asked myself, after all we did have an eight hour time difference between us.

So I decided to wait, messaging them at regular intervals. An hour passes, two hours pass, four hours, a day, two days, a week.

Still nothing.

At this point, I was about to accept that they didn't want to talk with me anymore, until I saw a notification on my phone from them.

I quickly opened the notification hoping that it'd be them saying they were okay and explaining why they were gone, but it wasn't.

Instead, I was greeted by a message from their parents, that had gotten the belief of me being some sort of child predator, and that they we're going to report me to the FBI if I didn't stop talking to my friend.

Now, I know that sounds insane, but trust me, it's true.

But what does any of that have to do with the bot?

Well, seeing as I no longer had anyone to talk to in order to rid my boredom during classes, I eventually shifted my focus to other places, those being programming.

Having grown up with RPGs like Runescape, FATE, Fable and more, I had always felt they were a bit lacking, and as such I wanted to make my own, where I had control of the game I was playing and what content was in it.

Having experimented with Discord bots beforehand, I decided to apply my love for RPGs, my small experience with Discord bots and my knowledge of programming into one project. DRPG.

I thought this was supposed to be code stuff?

I'm getting there, just keep reading.

When I started the project, I kept all the commands in one file, which after a couple of months proved wildly inefficient since it ended up being over 10,000 lines of code in one file, which you can see here.

So, I decided to rewrite it and split it up into smaller files, getting us to version 1.5, where I had split the commands into their own files based on their category, keeping the same sort of structure I had before.

Those also grew into monolithic files and as such, it was time to rewrite once again.

Version 2.

This time, I decided to keep the category concept I already had in the bot, but I still had the challenge of keeping the file size small and memory usage low.

To accomplish the first task, I took a look at other projects and I noticed a common pattern. The files were split.

Now, this was a bit of a new concept to me. Keeping every command in it's own file? How do I make sure they can all access the data and the utility functions they all needed?

I decided to write a semi-modular system that would load the commands automagically using the file system API built into NodeJS, aswell as move all the data handling to their own subset of modules to interact with the database I now had chosen for the task, RethinkDB, as previously I had kept everything in memory and saved it to files. (More on this in the next blog post)

For these database classes, I decided to export them all in one single package I would then make global.

let Classes = require(__dirname+'/Classes/index.js')

global.Classes = Classes

This proved to work for a while, until I found out about ES6 classes in late 2017.

Having used object-oriented languages such as Java and C# previously, I really enjoyed OOP as everything was easier to keep track of, which brings us to Version 3.

The OOP Rewrite

Now, don't get me wrong, the system we had was working just fine and it was easy to expand on, but the code was spaghetti, something I didn't enjoy at all, so I decided to rewrite it with ES6 classes for the commands, which made it all cleaner.

Along with rewriting the commands to classes, I decided to remove the global `Classes` variable in favor of having each command be fully modular, so it would only require the classes it needed, instead of everything which really helped out with memory usage and reduced the overall spaghetti of the project a lot too.

This was still in an early stage, and the code was still like an Italian restaurant, spaghetti everywhere.

This is when I decided to utilize a tool called JSHint, which helped me keep track of different syntax errors, missed semicolons and more in the code before I would deploy it to production.

This worked for a long time until I wanted to have it be directly in my editor instead of as a command-line tool, and it didn't support a lot of the new ES6 features such as arrow functions.

Only one thing to do. Switch tools.

After doing alot of searching, I decided to switch to ESLint, which is a pluggable linter, which in simple terms means you can configure it however you want and make your own configuration plugins.

What a ride it was.

Going through the code with ESLint after about six months of no linting proved quite a big task. There was errors everywhere, running it through the command line showed about 5,000 errors at least. Thankfully, they were easy to fix since ESLint gives you the exact position of where the error is in your code.

In conclusion

Having read through all this and reflected back on how this project has evolved, I've learned a lot from it, and here are some highlights.

Plan Ahead.

Always plan ahead for your projects, how many users are you expecting? 1,000? Build it for 10,000.

Maintainability

Always write your code as if your six-year-old cousin with no experience could pick it up and keep working on it once you've abandoned it.

Scaleability

Scaling up your project in order to allow for more features to be added on with ease is a must. Trust me, it will make your life so much easier when you can just drop a file in your project, deploy it and have it just work.

Testing

Don't test in production. Just don't. It leads to bad things, like that one time I made every item type in the game an egg, good thing I had backups.

Backups

Backup your data at regular intervals.

The worst thing is not having a backup when your server dies or when you manage to delete the production database again.

Version Control

Use GitHub to host your code, or GitLab, whatever works for you, that way you'll not only have a backup of your code, but you'll be able to see when shit hit the fan.


As usual with these posts, I end them on a joke, so yes Taylor, you can go play games or whatever you're up to these days now.