How Disgo Uses Copygen #32
Pinned
switchupcb
started this conversation in
Usecases
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Disgo - Create a Discord Bot in Go.
Credits and Contributors (People - Open Source).
What is the purpose of this project?
The purpose of Disgo is to allow users to use the Discord API with the Go programming language. Using the Discord API is a requirement to the creation of a Discord Chat Bot; which provide a variety features for the Discord Chat Application.
What are the technical challenges of this project?
The technical challenges of creating a Discord API Wrapper involve the challenges associated with API Consumption and Developer Productivity. The API Producer (Discord) themselves provide an API (HTTP, TCP, UDP) with many features that the consumer must implement a language-specific API (Wrapper) for. An end user of the API Wrapper (Developer) can use the wrapper's interface to spend less time on the technicalities of the API, and more time creating valuable business-oriented code.
One of the challenges involved with any API Wrapper is maintenance: The API Producer is bound to make updates which cause features to be removed or added. The Discord API is no exception and Discord makes the job harder due to the following issues.
On the other hand, we must always consider the end user (developer) who uses the API Wrapper to create code. Most API Consumer libraries create their own methods to consume an API Producer. However, this results in the developer having to learn two APIs (Producer and Consumer). This overhead can create a lot of confusion due to unnecessary abstraction, and pushes the code further from the data it represents.
How does Copygen help you solve these challenges?
Copygen allows us to guarantee every feature by generating code upon the types library. As long as that library remains up-to-date, issue 1 and 2 are not as problematic. Copygen also allows us to expand what is possible with regards to our implementation. As stated, most API Wrappers require the developer to understand two APIs. In contrast, Disgo can be used by a developer who only understands the Discord API. This is because every Discord Object, Request, and Event is defined as a struct. These structs contain the properties a developer would expect such as a
Send()
function for a Request andCommand()
function for an Event.This implementation also allowed us to avoid the use of reflection; an important feature with regards to performance. As an example, WebSocket Event Handling functionality is typically implemented (in other Go API Wrappers) by defining an
Event interface
and type asserting this interface — which isn't necessarily reflection — to the actual event at some point. As this was a hot path, we decided to avoid this by using logic that required us to continuously add cases for each event. Without Copygen, creating this logic — spanning 2000 LOC — would have been grueling and prone to errors; not worth.There are over 170 endpoints in the Discord API and creating create
Send()
functions for them all results in ~2000 LOC. When Discord adds more endpoints (as they have recently), all we have to do is add a few lines to a setup file and run a command to remain up-to-date. As a result, we not only create code fast, but maintain it with ease. Writing 3000 lines of code would take an average programmer one month, and possibly more to refactor it. With Copygen, we were able to do this in less than an hour.Thanks to Copygen, Disgo took 5 - 6 months to do what has taken other libraries years; DiscordGo is not feature complete after 6 years.
Using Copygen
Copygen Version:
v0.4.0
(GPL - Free)Requests
Copygen Feature Used: Custom Generation (
.go
)Example:
wrapper/requests
The library defines requests as structs, and developers can send them using a
Send()
function. In actuality, aSend()
function must be created for each request. There are over 170 requests, and some use different content types (i.e URL Query String, JSON, Multipart Forms). As a result, we required custom generation in order to not only generate the actual functions, but to customize them depending on the properties of the requeststruct
. This resulted in approximately 2 KLOC.Events
Copygen Feature Used: Custom Generation (
.go
)Example:
wrapper/events
The library handles every WebSocket event that Discord provides through the use of event handlers. This poses an additional problem regarding how a handler is stored. This resulted in us using Copygen for 4 components of the event handling functionality:
Handle()
andRemove()
handlers, storing handlers in aHandlers struct
, andhandle()
ing the event upon a payload. This resulted in approximately 2 KLOC.Commands
Copygen Feature Used: Custom Generation (
.go
)Example:
wrapper/commands
The Discord API features commands which are payloads that can be sent to a Discord WebSocket Connection in a similar manner to an HTTP Request. As a result, Copygen was used to generate the
Command()
functions.Coverage Test
Copygen Feature Used: Custom Generation (
.go
)We used Copygen in order to generate the base of a test that covers nearly 100% of the Discord API. That process is described here. This resulted in approximately 2 KLOC.
Beta Was this translation helpful? Give feedback.
All reactions