Build A Bot (DiscordJS) — A Bot Factory and Revealing Module Design Pattern

Konrad Abe
6 min readFeb 8, 2021

--

Last time we made our commands more flexible and improved the structure of our code for better readability and scalability. This time we will turn our simple bot into a bot factory, allowing us to use it to spawn multiple bots with different configs, using the well-established Factory and Revealing Module design patterns.

SERIES: Build A Bot (DiscordJS)
1) Javascript Chatbots made easy
2) A scalable setup with command modules
3) => you are here <=
4) Better Logging And A Persistent Bot Config

Things you should know for this part include scope and closure of Javascript functions as well as es6 basics (const, let and fat arrow functions)

Transformation

As I said, we will transform our previous code into a factory function. This means that we will rely more on parameters and configuration given when using the factory rather than when setting it up. So, first of all, let’s clean up a bit. We’re going to throw out a lot of our old code.

Then we will wrap all of our remaining code in our factory function and call it createBot but if we were to simply return the bot object, which we used until now, this would mean that everything within this function will be bundled together and publicly available. We don't want that, do we?

To make sure we control what is visible and accessible from the outside, we won’t return the bot object itself but only the functions that need to be usable. In our case right now this is only the bot.load() function. Thanks to the closure, the bot object will still be there and remember all that we need for our bot to run but access is limited to what we pass to the return function. This is often referred to as the Reveal Module Pattern.

Add a return {} to the createBot function and only define one attribute as start() that will call the load function.

The last thing to add now is the module.export with our createBot function.

You might have noticed that I did not use the correct indentation here. To show you a better screenshot, I simply kept the indentation (even though I wrapped the code in a function) so that the diff would show exactly what I changed in each line.

I will correct this before we move on.

GitHub Commit (changes)

Adjustments

As we will get our config handed in from now on, we need to make a few minor adjustments. First of all, we need to rewrite our bot.load() function as follows.

The new load() will expect a config object with mandatory (token) and optional (name, prefix and later other) attributes and attempt to merge them with our configSchema in loadConfig(). Our old code will be passed into loadConfig() as a callback here.

In loadConfig() we will check if our initial config is there and contains a token. If either check fails, we will throw an error. Otherwise, we will merge the initial config with our configSchema and attach it to our bot before we execute the callback code.

We need to make a small adjustment to grab our prefix from the new config and then we’re done here.

With our factory in place, it’s time to add the bots. For this part to work properly, you would need to head over to my first instalment of this series and create a second bot via developers portal but you might as well just make an array of 1 bot and go with it.

Create a new index.js at the root of the project. This is where we will import our factory, load our .env variables containing our tokens and add the configs for our bots. Without an array of bots to start, this would be the way to start a single bot with the factory.

If you have only one bot, it’s super easy to start it. Create the bot using the factory with your config and run the start() that is publicly available.

You are done!

If you want to define a group of bots to run from your project, you can simply do so in the config file.

If you name your tokens in your .env file accordingly, you can map them in your config file like this.

Running our new index.js file will now start as many bots as you have entered in your config file.

If you have given them different prefixes, you can now interact with them as if they were fully independent bots. Should you use the same prefix for both bots, both would react to the same command.

With one final adjustment to our package.json to switch to the new index.js file we are now done and can spawn as many bots as we like (and have registered with Discord)

One word of advice though.

If you are running bots on your own server, this way of creating multiple bots is ok. If you plan on hosting this bot on many servers to be used by many people, grouping more than one bot together is not advisable because it can lead to performance issues.

In that case, it would be better to reuse the code for the factory (for example by submitting it to and loading/importing it from npm).

Bonus

You might have noticed that our new console log for multiple bots does not tell us which loading message belongs to which bot. To amend this, I’ve made another minor adjustment to add a short tag to those messages.

Git Commit (tagged logging)Link to the finished code / tag v0.0.3 on GitHub

Wrapping up

We’ve turned our bot code into a bot factory and used well-proven and time-tested design patterns along the way.

Next time I will guide you through the process of writing a scaleable and self-updating help command as well as adding our first user management/administration commands to make the bot a bit more useful.

Some words about me:

If you want to see more of my work and progress, feel free to follow me and check out my other articles. If you clap feverishly for the articles you like most, it will be easier for me to decide which directions to pursue in following articles so use your ability to cast a vote for future content.

I’m also currently working on other series covering complex React Native Setups using Typescript and scalable apps with Redux, where I’ll go into details about how and why I do stuff the way I do as well as some articles on my experience in building games for web and mobile with React.

Here are some of my recent topics:
- React Quick Start with Typescript, Redux and Router
- Linting/Prettier with Typescript
- Redux + Toolkit with Typescript
- Spread & Rest Syntax in Javascript
- clean and simple Redux, explained
- Game Theory behind Incremental Games
- Custom and flexible UI Frames in React Native

And if you feel really supportive right now, you can always support me on patreon, thus allowing me to continue to write tutorials and offer support in the comments section.

--

--

Konrad Abe
Konrad Abe

Written by Konrad Abe

I’m a Web / App Developer & father 👨‍👩‍👧 doing freelance and part-time agency work since 2003, 💻 building stuff on the side 🕹 and attending conferences 🎟