While planning the creation of a community, I needed to implement effective moderation among other automated tasks. Using the Application Programming Interface (API) provided by a messaging platform would allow me to implement these features in a Chat Bot. To be specific, an API represents a definition on HOW to communicate (from computer to computer) within a network. A Chat Bot is an application that communicates by making requests (from one computer to another) to use an API. An application (that is run on a computer) makes requests by executing code (created in a programming language). The code of an application that makes requests to an API is called the API Wrapper.
Discord is a messaging platform which has permissions for moderation purposes, communication channels, threads, forums, voice chats, screen sharing, events, and the ability to automate via an API. Discord alternatives include TeamSpeak, Matrix, Harmony, and Guilded. However, none of these platforms are as feature-rich as Discord yet; with the exception of Guilded which lacks an official Bot API. In addition, I have used Discord since 2016. As a result, I decided to use Discord as a messaging platform for my community.
This choice is significant because a Discord Bot is a server-side software (that operates in a distributed system). In addition, the programming language choice defines the API Wrapper options. For example, I was not using NodeJS, so using the DiscordJS API Wrapper was not a viable option (regardless of its issues). Go has multiple Discord API Wrapper implementations, but I would find these to be sub-par (explained in the Project Timeline). As a result, I needed to create a Discord API Wrapper for Go to create a Discord Bot (in Go).
Create a feature-complete yet maintainable Discord API Wrapper for Go.
What is Dasgo?
Dasgoprovides a direct representation of Discord API Objects in Go. Using dasgo to generate or alias the structs of a Discord API wrapper or bot saves developers from maintaining over 4000 lines of Go code. As dasgo gains adoption, users will benefit from code that is reviewed by more people and updated quickly.
What is Disgo?
Disgois a Discord API Wrapper designed to be flexible, performant, secure, and thread-safe. Disgo aims to provide every feature in the Discord API along with optional rate limiting, structured logging, shard management, and caching. Disgo is also the only Go module to provide a 100% one-to-one implementation of the Discord API.
The features and capabilities of Disgo are easier to understand by considering the limitations of the current Discord API Wrappers.
Go API Wrappers
Disgo is the only Go API Wrapper using a maintainable approach to achieve feature completion. Disgo is the only wrapper to define API definitions (objects, requests, commands) as structs, allowing for usage of the Discord Producer API without requiring knowledge of an additional API Wrapper Consumer API.
With regards to performance, Disgo is the only Go Discord API Wrapper that doesn't use reflection in its hot-paths (aka main functionality; requests, events). A precise selection of dependencies (explained in library decisions) allow Disgo to maintain the most performant code.
Synchronized memory pools are used for objects that are constantly created. Disgo's cache is optional. A fieldalignment bundle is used to save memory on otherwise large structs (defined by the Discord API). As a result, Disgo does not require as much memory as cache-first Go API Wrappers, nor does it invoke the Garbage Collector as frequently.
The following information includes a direct comparison of Disgo to a Go API Wrapper library.
Whenever you scroll down to the footer of certain websites, you'll see a phrase that says, "made with love" or some boolshet like that. This project timeline is the opposite because this project is what made me realize that everything I do is motivated by anger. This is a project timeline of a boy becoming a man by creating a project that took 150 people 7 years... within 6 months. Here lies my journey in creating the most performant feature-complete Discord API Wrapper in Go, while learning about everything that is wrong with the software development industry.
Looking back I've realized that people I'm surrounded by haven't been the best influence. I wanted to host a community because the people I interact with from my channel are awesome. The Earth has multiple sides and I've spent most of my time with people who laugh at kids being shot down while the shooter streams Doom. However, there is a side of Earth out there full of people whose life is peaceful. I have been aware of these people from my youth, but my upbringing led me to pick the wrong side. As a result, I must exert effort to connect with peaceful people.
The API Wrapper
I created the Discord Server (called a guild) for the community on March 1st, 2022. I would spend the following days adding as much functionality as I could without programming. There are many ways to solve a problem and programming is simply one tool to do so. Once it was time to implement custom functionality, I looked into three Discord API Wrappers created for Go. Unfortunately, I'd quickly find out all the issues these wrappers had, explained in the previous section. For more information, read the State of Disgo (v0.10.0); which includes a summary of my initial findings.
I would use the DiscordGo library for a few days until I encountered a few errors. I attempted to solve these through multiple issues and pull requests, but the promise (read: limitation) of Backwards Compatibility was enough to recognize that these changes would fall short in some way. In addition, Russia (where the maintainers live) was being sanctioned. At this point, the decision was obvious. Use DJS. DiscordJS has issues. Instead, I decided that I would create a Discord API Wrapper for Go that didn't have any of these problems. Besides, Discord was a company worth $15 billion baller dollers.
How hard could this be?
I reached out to over 10 people (including 4 women) and asked if they wanted to assist with this task. 3 men gave me the ol' Wagie World homework excuse while the others ghosted me like the response a company gives an r/programmerhumor user. Fine. Have fun being L3... That left Thomas — a college student — and Daniel, who I worked with on 11503 Hyperfang: Rover Ruckus, Audius Enhanced, and a Failed Startup.
Every problem I experience going forward is only an issue with people. That's because programming is a product of humans built upon by other humans. To be specific, I experienced problems with Discord employees — who get paid to be extremely inefficient — and the entire wagie world that follows.
The first person to cause problems is Daniel.
On April 16, I started to troll the Go issue tracker by submitting fundamentally valid error proposals using meme language. Everyone knows that error handling is a psyop implemented by Russ Cox himself to scam Google into spending millions per year on Generics. Don't believe me?
He got paid 1.2m a year to ignore the languages most voted problem (since Generics passed) when his proposal failed. We paid him $4 million dollars and 5 years later, we still have to use 3 lines to handle errors. THE AUDACITY!
On the other hand, isn't $1.2m per year a bit low for one of the BEST programmers in the world? Not very motivating is it... Oh well. Slaves built America's economy and got paid nothing for it. Now their children suffer and what can they do? Suing a dead slaveholder for theft is like suing Bernie Madoff in jail. You're not going to win the lawsuit, and even if you do his kids won't give the money back… Anyways.
Daniel sees this trolling and says he doesn't want to be associated with me on GitHub as if he was a major contributor. He has 0 commits. On every public project I have... Look at his profile (at the time of writing). 0 stars. 0 forks. That means no developer impact.
Thomas and I were putting in the — as Daniel would call it — "shitter" work that was literally the fundamental piece of the program called Dasgo which contained the types that would be used to automatically generate the API Wrapper upon a Discord API update; since Discord wouldn't provide a machine readable API. I tried making an IC1 bring up a machine readable API in his retrospective meeting (he brought down production) but there was no hope. The Boomer Discord Developers are stuck in their ways.
The following paragraph references an event that occurred in 2021. Everything eventually becomes relevant. Bear with me for a moment.
Daniel and I once had an argument during our failed startup. This conversation occurred after 500 hours were logged; with 400 hours being logged by me. At some point in our work, Daniel became staunchly against logging his time. He argued that we did not need to track our time to prove we were providing a fair value to the business. I did not agree, so after a few weeks I performed an analysis showing his contribution to the startup which was 1% of the codebase and a shitty outdated diagram that got scrapped when he wasted $7 of mine without any care in the world. That's right. My first failed startup cost me 400 hours and 7 bucko BUCKS. The significance of this is that I knew that he had a low chance of contribution, so him quitting didn't surprise me.
Now don't get me wrong. Daniel is a smart guy. Genius even. However, his inability to work with people is going to be what prevents him from success. Just kidding. Daniel is the type of guy who aces LeetCode without issue. He will have no problem getting by effortlessly. Still much better than an average programmer anyways...
College is increasingly becoming irrelevant to the software development field. Students go 4 years without using Git... I could go on about this for hours but the craziest part about college for me is how "productive" it actually is. We have students whose lifetimes span 22 years to benefit a total of... 0 people. OK maybe that's a bit extreme. They do line the pockets of student debt loaners...
So after all this time spent learning theoretical boolshet, we give them this huge piece of paper and ceremony with it. They feel really special, "smart", and prestigious. Yet fast food workers have provided more value to society than them. It's no wonder narcissism is growing among college students...
This is relevant because while we are doing all of this, I'm — like Daniel — considering dropping out to get a REAL JOB. Or at least that’s what I thought he meant. This consideration was motivated by the countless posts I saw on r/cscareerquestions full of people saying they got jobs, but who had no stars on GitHub (read: can't code). Then there was the whole Discord Machine Readable API fiasco. Finally, an anecdote from a 7 year old.
People are being paid hundreds of thousands of company coins to sit around all day. Why not do that as well?
I went around asking REAL ENGINEERS what title I should be applying for. Some told me that — because I was able to take a client project from start to finish without help — I would be a Senior Software Engineer. Not to mention, all of the projects and contributions on my resume. Everyone says this except for a guy we will call Tim.
Tim starts the call by saying that he knows everything since he just got his degree. Let's say that Tim is your stereotypical r/programming poster. Knows everything about programming and non-programming topics and looks down on the liberal arts... I ask about the tech stack he is using at his job (which he has worked for a year at), and he "can't tell you [me] what it is". I send him my website and he calls it wack before the page loads. I'm pretty sure it doesn't load that fast.
Tim eventually finishes his rant and says that I'm not a Senior because I have no degree. Keep in mind that this is after the Achievements For Thee (Coming Soon) experience with my parents, so my mind is literally being sadged. Tim ended the conversation with, "y'know what, you might be a better programmer than me but I will not take your advice cause you're not Senior". These are the people I have to deal with for the rest of my career. Is this really an industry controlled by Credential Gatekeepers who see the world in this way?
Tim was right.
I applied to 30 companies for a number of Mid - Senior Level Go Backend roles. To be fair, this is a low amount; nor does it include common companies such as Microsoft, Apple, Netflix, or Quant funds. Some companies never responded or are just responding now. With that being said, here are some notable experiences.
I decided to apply to Discord due to the lack of information about the Discord API in the Discord API Documentation. Unfortunately, the recruiter at Discord rejected me with an automated message. I might have made them mad by writing in their stupid little dynamic form that I — a demographic filling 4% of the software industry — have never experienced a diversity program in Tech. In fact… Why do you think only 4% of the software industry is black? Because the world hates black people.
In reality, I got rejected because “the position fit was not good”. Let me give you a tip. When a company sends an automated rejection with no real information, it means that you can interpret why you were rejected and reapply as necessary. Besides, I already applied to three of their positions. I decided to find the recruiter's personal email and asked why I was rejected (to improve my resume). No response... The next "automated" rejection letter was much nicer though 🙂
After viewing the resumes of a few actual Discord employees, I was likely rejected — despite my “impressive background” — because I was never “employed”; rather contracted. Either that or the fact that I was still in college. Or nepotism. Check out this story from a Discord Employee.
“If I could give one piece of advice to younger-Ian, it would be to view networking less cynically. I always thought of networking as making connections with older, more established professionals - in a way that was almost transactional. In practice, this has almost never been true.
My network is organic. It's who I talk to daily and weekly, outside of a professional capacity. My college friends helped me get a job at Zillow. Online friends helped me get an interview at Discord. Twitter mutuals I shitposted with got me my contract job with the Anime Awards. I've realized that my network isn't something I have to force, and I'm much less cynical for it.”
Something. Something. If you don't recognize who the <insert trait> in the group is... Maybe it's... why multiple developers are paid over 6 figures and still can't explain how their own API works. What’s more important is that our chances at a Discord Machine Readable API were GONE.
After this entire experience, what advice do I have for prospective programmers? Don't waste your time on Open Source. Don't make the world a better place. Just focus on yourself. Do more LeetCode. We live in a Wagie World.
Wagie World Woes
From May 7th to May 26th, Thomas got caught up in some Wagie World Woes (finals). As a result, he “forgot the project even existed”. During this time I finished up Dasgo, except for a final specification edit. I also created the generator command necessary to generate over 10,000 lines of maintainable code. For more information, read about How Disgo Uses Copygen.
On May 29th, Thomas and I had a talk about the Wagie World: "Thomas, there are currently only two known types of programmers in existence: .1x and 10x…" Fast forward to the end of the week, and I had finished the OAuth2 Flows and HTTP Retries while he had "finished" the WebSocket code. Progress was being made.
An unemployed college graduate named Josh Dawe needed help. I gave ‘em a job alright. After a night of mentoring, Josh finished up Dasgo by implementing the final specification on June 6th. After that, I tasked him with OAuth2 Unit Tests. That's all he needed (along with ATS Resume advice) to be successful. “He got the job.”
I would spend another week "finishing" WebSocket Code while Thomas got paid $50 an hour to watch videos related to orientation all day at his internship. Meanwhile, Daniel was also getting paid to watch videos all day at an internship… These interns get paid $XX to watch videos the whole week; and paid more than the creators who made the videos in the first place. Meanwhile, in Africa...
On June 8th, Dasgo was merged into the official Discord API Documentation.
We had originally planned to release Disgo in the week of June 20th. However, we still needed more tests along with a working rate limit implementation. I was halfway into implementing rate limit functionality before I realized that the Discord employee who created the original PR for the rate limit documentation had no idea how Discord implemented their rate limits. This meant that I would have to do experiments over and over until I finally got it right. While all of this was happening, people kept missing scheduled meetings.
Progress slowed to a halt until July 5th. All my time was being wasted to determine the rate limit implementation. Josh was dealing with his job offer. Thomas was bogged down by his internship. This led me to engage in a long period of thought; where I would stare into the void for hours in an attempt to assess the situation. "Fuck. We're blocked."
A deep sense of shame overtook my body: Were we really going to go 4 months for nothing in return? When people don't really understand the importance of these projects (enough to be motivated), what's the point? Then, I had an epiphany. You can imagine an equivalent to Newton’s Apple, but I’m Newton and the apple is a lone Amazon Recruiter marching their way into my inbox. At that very moment, there was only a single thought to be had.
"What would Bezos do?"
I told the wagies that I wouldn't give them future job referrals unless we finished the project in 14 days. It worked, sort-of.
From July 13th to July 14th, I refactored websockets. I fixed the tests of websockets. I fixed the heartbeat functionality of websockets. I fixed the disconnect method mutex semantics. I added a reconnect method to websockets. I sped the tests of websockets from 45s to 6s by using a jitter interval trick. I fixed the data races of websockets. I added commands to websockets. I updated the documentation for websockets. I added CI for websockets. I merged websockets.
On July 15th, my ass got blown up by a Mexican restaurant.
After all of his hard work on Dasgo, Thomas was exhausted. "I hate this project. Every day I come home from work, and then I do more work. When I work on Disgo, it is my life. Once we finish this project on July 21st, I'll never work on it again." You know what else gets this attitude? School projects. I decided to up the complexity of assignments on Thomas so he'd take more ownership.
A Full Coverage Integration Test
I had this idea for an Integration Test that would grant us full coverage of the Discord API. One that would make Disgo the number one API in terms of reliability. For the unaware, an integration test is a test that interacts with the real-world environment. Remember when HBO Max sent a test email to all of their subscribers? Yeah. That’s an integration test gone awry. In any case, an integration test is used to ensure that your code provides the functionality it promises.
Thanks to Dasgo, we already had every feature, event, and route (176+) in an automated pipeline (via Copygen). All we had to do was call these routes (and respond to these events) in an optimal manner; to save time on CI. Once Thomas understood the task, I gave him full jurisdiction to find a solution. Unfortunately, he got blocked immediately.
I drafted up a plan fairly quickly since we were so close to the official release and I wanted to save time. The plan included a 4-step process to find the optimal request order for all 176 Discord API Endpoints by using data input and a topological sort. That’s right. For the first time in my career, we were using something I already did on LeetCode.
There was a problem, though. Despite my explanation on the issue we were solving, the task at hand, providing the theory to the solution, AND the public commented code (I created), Thomas could not figure out how to implement a solution within 3 hours. An entire 3 hour call was wasted on ??? I spent the last 20 minutes finishing the task up for him (with an explanation) while he watched. Now Thomas is a hard worker, but THIS AIN’T IT! I realized that something was extremely wrong, but I didn't understand it until later.
Josh spent time with his girlfriend since he had to move due to his job. Well, that's definitely not what happened. Josh had his first programmer moment and faced impostor syndrome upon being assigned examples. It was causing way too much stress in his life; in addition to the move his job required. I decided to help him out and cut him from the team.
From July 16th to July 19th, I'd refactor WebSockets to provide better stability to the connect, disconnect, and reconnect functionality. I would identify and fix all data race issues. I would also add Gateway Commands on a call so that Thomas could learn how to use Copygen. And I'll admit. My mental concurrency models needed work. These tasks upgraded them.
With the major WebSocket features out of the way, all I had left was to merge Rate limits. Thomas had to put the test together, and used Copygen to save himself from writing 2000 Lines of Code. For the first time, Thomas was becoming a 10x. We had planned to release the project on the next day (July 21st), but we faced an oversight regarding the tests finalization. After this realization, we made yet another discovery on Discord's entirely non-uniform non-standard rate limit per insert thing that requires optimization.
This comment by Discord sums up the Developer Experience entirely: #2190-816363129. The documentation tells us to use a token bucket algorithm for rate limit handling for EVERY ROUTE. There are 176 routes which would imply 176 different token bucket rate limits. In practice, certain routes don't have rate limits; instead using the Global Rate Limit which is actually a fixed window rate limit. API developers are told to rely on the rate limit headers Discord gives, but then Discord admits that they can always be inaccurate…
So imagine getting through all of that only to realize that Discord also has these magical "per-resource" rate limits that are explained in the most confusing language you have ever seen. "Emojis don't follow conventional rate limits and top-level resources have their own rate limits." What the fuck does this mean??? FUCK! Rapptz was right… I looked for inspiration from the community (DiscordGo and other wrappers), but they don't even handle it correctly (after 7 years).
I would eventually figure out the full implementation around the release of Disgo Beta. However, I was not going to create an implementation until the Full Coverage Integration Test was complete; since it would allow me to confirm my findings. Once this occurred, Disgo would be the only API Wrapper featuring a complete and correct rate limit implementation for the Discord API.
The Beta Release
Disgo was not supposed to have a beta release. In fact, everything listed in #11 — which is everything except sharding, caching, and voice features — should have been completed after 5 months (March 1 - July 26) of working on the project. I changed my mind for two reasons. First, it was around this time that I had the onsite at Amazon, so placing the project in a releasable state would be beneficial for me. Second, Thomas decided that this was the last day he would work on the project “for a few months" so he could relax until school started. Regardless, it became clear that we wouldn’t have finished even if Thomas continued to work.
Thomas and I were taught the basics by the same teachers, but somehow he became a spray and pray programmer. Remember when I realized that "something was extremely wrong"? This was it. Why couldn't Thomas put together the modified topological sort in 3 hours with everything he needed in front of him? It was because he viewed code as the ends rather than the means. A spray and pray programmer does not think about the lines they are writing. They take what they are told to do and hope for the best. This results in copied examples and hoping the code just works, rather than looking at each line as an action in a series of steps.
When this type of thinking permeates into a lifestyle, you get a modern wagie. Doing something because everyone else does it, with an illusion of an end goal in mind. It's impossible to motivate someone with no real end goal. This is why Thomas was unable to contribute much when the implementation wasn't spelled out for him. There is no critical thinking or individual actions when you spray and pray; only vague plans manifested by others (i.e College). Sometimes these plans work for you, and sometimes they don’t.
Thomas and I would work together to eventually fix this issue (of spray and pray programming). However, at that point in the project, it was clear that he was not going to finish his task (even if I gave him months to do so). He himself admitted that the achievement of Disgo wouldn’t be something he was able to comprehend. So I can understand why the motivation wasn't there to finish: From his perspective, we were doing work for the sake of it with no end in sight. Thomas is a great person, but it didn’t change the fact that the project would be delayed and I was — yet again — stuck with his workload.
*The following sections were added on December 15th, 2022.
From August 9th to November 2nd, I was unable to work on Disgo due to a variety of reasons. For one, it took my new apartment complex 63 days to fix every issue with my unit from the date I moved in. During this time, I released the SwitchUpCB Guide among a host of other features. When I got back to the OSS scene... nothing important happened.
While I was gone, Discord released a forum channel feature. Thanks to Dasgo, all of the API updates from the PAST 3 MONTHS were implemented in 3 hours. Thomas was nowhere to be found once school started, except for assistance with marketing. As a result, I finished up the full implementation test; alongside the remaining features for an official release.
I applied to a number of companies from August to October. Notable experiences include My Chainlink Interview Experience and My ClickUp Interview Experience. The significance being that passing technical interviews didn't matter. There is nothing I can do to appease these people because they want "experience": A cop out for fortunate. It's all a Game of Chance. Credentialism. Numbers.
I submitted Disgo for recognition among various communities but kept getting pushback. Discord made the API recognition a popularity contest. The Discord Go community started to attack me for making a library that was more performant and feature complete compared to EVERY one of theirs. DiscordGo fanboys started calling me a "shady and downright bad person" and the moderators of r/golang protected their attacks while deleting my responses.
Well, I also uncovered some other things...
As a result of the above, the stable release of Disgo and its respective promotion only managed to gain the repository 18 extra stars for a total of 38. FUCK! I needed Disgo’s recognition to improve my resume. More so that this experience reconfirmed my conclusion that software development is not a meritocracy. The library I created was better in every technical aspect, yet its recognition was being limited by politics.
I decided to run a campaign.
Disgo is the successor of DiscordGo. Rapper destroys Google Software Engineer in API Development. I put these programmers on pack watch. All of these articles exposing the poor technical decisions of the existing API Wrappers. Did it work? Will it work? Doesn't matter... Disgo is completed. The Discord Bot will be finished. I have learned how web development works. I have learned how the software industry works. I have learned how normal people act. I have adjusted accordingly.
You can track the release progress of Disgo on GitHub.
A Waste of Time
At the start of the year, I was on my ass looking for a way to become a normal person. No matter which way I looked, I realized that money was the only thing holding me back. I have potential in many aspects of my life, but need the freedom to execute those aspects. While I may have improved my skills in these aspects in the last 8 months, I am still without enough money. I am still held back; maintaining more potential in these aspects. In a way, I am in the same place as I was at the start of the year. What a waste of time.
At least I’m not in hell. I just need to stop making articles such as these.
On the other hand, Discord’s API showed me how much of this industry is truly a grift. It boggles my mind how one can create a system with the purpose of others using it, only to make it impossible for others to use. I shouldn’t have to waste 2 months (and more) to adhere to your rate limit standards. At the very least, provide a coded example for the consumer (developer). Let’s not forget that Discord’s API Documentation is mainly built off the backs of bored high school students. It’s things like this that showcase an inefficiency the industry has yet to exploit.
I canceled my Nitro subscription.
Despite these setbacks, we were still able to create a usable solution. Thomas — who started out as a noob — even contributed a few KLOCs. This guidance is why I should be classified as a Senior Engineer, but a lack of credentials causes jobs to place me at a Junior or Mid-Level role. It has become obvious that some level of spray and pray is required when the world uses it to evaluate everything.
At the end of day, Daniel got into the University of Texas (following his internship). Thomas made big bucks at his internship. Josh relocated to his job. Everyone was making money, except me. Well… In the eyes of Capitalism, they are better programmers than me. I can't argue with that. It's time for me to waste another month on LeetCode.
What do I have to say about this project? I learned a lot. Definitely accelerated my programming career. However, it's not that fulfilling. In hindsight, there is no reward in Open Source. I look up at the stars at night and wonder if I made the wrong choices in my life... Oh. Look. Copygen hit 200.
I once gave a prostitute on the internet advice on how to code; since she was looking for a career shift. Sent the roadmap and resources and everything... However, I feel bad now because pursuing software development might just increase her suffering. I was at a hairdresser when it dawned on me that most people's lives revolve around people; not their career. They go to work, speak with family, and come home to a community. Work is just a means to an end.
Accountants don't interview other accountants by giving out LeetCel questions or attempting to downplay each other's queries. They just ask who your father is. This is in stark contrast to Uber's Leo Horie, who — upon reading some fake story I made up about placing a GPL license in a take-home interview assignment — went out of his way to state how wrong it was, then downplay the complexity of the problem Copygen solves since "it took him [me] 2 weeks". Gave me a chuckle, ngl.
Alright, so now for the real reason you clicked on this post. How did 3 people create a project that took 150 people 7 years in 6 months? Let's do the math: 3 people * 6 months = 18 for a feature-complete State of the Art API Wrapper. 150 people * 84 months = 12600 for an unlinted, poorly maintained Garbage API Wrapper. 1 person mentoring 2 people means those people grant a handicap of ½ or .5. This results in the following equation: 12600/(18 * .5) = 1400 which makes me a 1000x programmer. So that's how.