Table Of Contents
- Introduction
- Replying and RestAction Failure
- Always do extra work on Embeds
- Use Configuration
- Conclusion
Introduction
When starting to develop Discord bots, I knew nothing about it. I even had problems getting the bot online, because I didn't understand how token's worked. It took me a embarrassingly long time to understand some of the quirks and functions of the discord API, and me being relatively new to the coding space didn't help a bit. I want to share some of my experiences and a bit of corresponding advice with other developers, to lessen their suffering or for you to laugh at my issues xD.
Replying and RestAction failure
When working with any sort of event (buttons, modals etc.), you have to reply to it any form, be it a message, an edit, or just a defer. But often I did something like this:
api.listener<ButtonInteractionEvent> { event ->
SomeLongExecutingFunction()
event.reply_("A peculiar message").queue()
}
This always caused an ErrorResponseException
, which then halted the whole event's process and broke several functions. It took me long to understand why this was happening until I read the error message which stated that "[t]his interaction took longer than 3 seconds to be acknowledged", which then brought me to the realization that what I was doing was stupid and redundant.
So after testing a bit and reading around 100 StackOverflow posts, I found the most simple solution to this was:
api.listener<ButtonInteractionEvent> { event ->
event.deferReply(true).queue()
SomeLongExecutingFunction()
event.hook.send("A peculiar message").queue()
}
This simply prompts the user with a bot thinking message and gives the bot a longer time to wait before replying to a message. It's such a simple solution and makes me question my own IQ.
Always do extra work on Embeds
When firstly starting to work with Embeds, I did only the most minimal work, in styling them, as possible. I thought that it would look good either way, but they often turned out as something like this:
val embed = Embed {
title = "Lorem ipsum dolor sit amet"
description = " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."
}
After some time I decided to put in some extra work to make them look better, which taught me some good advice.
1. Some color can make a huge difference. It doesn't have to be the most vibrant color, but even a slight red tone, can make an Embed look so much better:
val embed = Embed {
color = 0xE74D3C
title = "Lorem ipsum dolor sit amet"
description = " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."
}
2. When a message is about a single user, or references them in a particular way, always try using mentions and thumbnails/author. It makes makes the message stand out more and gives it a personal vibe:
val embed = Embed {
color = 0xE74D3C
author {
name = event.user.globalName
iconUrl = event.user.avatarUrl
}
title = "Lorem ipsum dolor sit amet"
description = " Lorem ipsum dolor sit amet, ${event.user.asMention}. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."
}
Or the same thing with the bigger thumbnail:
val embed = Embed {
color = 0xE74D3C
thumbnail = event.user.avatarUrl
title = "Lorem ipsum dolor sit amet"
description = " Lorem ipsum dolor sit amet, ${event.user.asMention}. Aliquam lacinia eget odio nec fringilla. Aliquam fringilla vulputate quam. Curabitur commodo nisl lorem, eget eleifend odio commodo quis. Vivamus non enim porttitor, ornare ex nec, pellentesque lectus. Integer mollis accumsan lacinia. Nam in libero egestas, lacinia nulla a, vehicula urna. Nullam."
}
Use Configuration
This is a thing I realized fairly fast, but still took some time to really internalize. There are many values you need to enter into your bot e.g. token, secret, activity, messages, embed content etc. It is a bit of a hustle to make all of that configurable but it will pay off in the end. As an example look at these two snippets of code, which one looks cleaner?:
First the one without any configurable values (configurable meaning not editing the code itself but something like a config.yml
that holds the values):
val api = light("mySuperSecretToken", enableCoroutines = true) {
setActivity(Activity.of(ActivityType.PLAYING, "/help"))
}
And the second one with configuration:
val api = light(config.settings.token, enableCoroutines = true) {
setActivity(Activity.of(ActivityType.PLAYING.takeIf {
!enumContains<ActivityType>(config.settings.activityType)
} ?: ActivityType.valueOf(config.settings.activityType), config.settings.activityContent))
}
At first glance, the second one seems more complicated but that just comes from the handling of probable miss-configurations, by providing a base value for the activity type that is used when the config value is missing or configured incorrectly.
But this provides so much value to normal users, or even for yourself as the developer:
- It is easy to change these values whenever you like.
- When you are working with longer compile times (e.g. Docker Images), it can make your work so much faster
- You don't have your token in the compiled program
- You are able to easily share the project/make it open source without having to search through your code for secret values
- ...
Then we have an example for a normal text reply, either you use a hard-coded solution like this:
event.reply_("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eget. ").queue()
Or you can just create a special translation configuration that stores all of these texts:
event.reply_(translation.lipsum.textPlaceholder).queue()
It even opens up the possible implementation of multi language support, by just creating multiple translation files e.g. en_US
, en_UK
, de_DE
etc. and then just using a single Serializer to convert all of these files to the same usable format.
Conclusion
These are just some of the things I learned while developing Discord bots, but they are the most significant ones. I hope that you somehow enjoyed reading this article and hopefully were able to learn something from it. As this is my first article ever, I would appreciate some constructive criticism (btw. english is not my mother tongue so I'm sorry for any language mistakes).
If you want to check out some of my work, you can look at my GitHub or the project were I implemented all of this/learned it:
Vxrpenter
/
SCPToolsBot
⚡ A discord bot application for usage on Scp Secret Laboratory servers

SCPToolsBot
What is ScpToolsBot
ScpTools Bot is an application to enhance your Scp Secret Laboratory server by providing quality-of-life features in combination with moderation and team management tools It also integrates with plugins like cedmod to build on already existing infrastructure and to use features they offer.
For more information check out the wiki or join the discord:
What Features are included
Feature | What is this |
---|---|
Fully customizable translation | All text can be changed to anything you can imagine, there are even color codes and other utility functions for even more customizability |
Configuration options | Many features can be changed to personal liking, e.g. disabling a certain part of it or enabling something else that is not active by default |
Status bot cluster | A cluster of bots that show the player count of your server. They also send connection messages to a channel that was configured by the sysadmin, that show |
Sources:
- The cover image was taken from discord's official branding page
- The placeholder text has been taken from the Lipsum page
- The code examples were written in kotlin using the JDA and jda-jtx libraries
Top comments (0)