RFC(builders): The interface, the validation, and the pains you have had with them so far
See original GitHub issuePreface: this RFC (Request For Comments) is meant to gather feedback and opinions for the 3 issues that will be mentioned down below. I understand builders tend to be quite a sensitive topic with everyone disagreeing on how it should be done, so please keep the feedback useful. Thanks!
This RFC aims to solve (hopefully once and for all) the three pain points of builders as they currently are done. The end goal is to decide what the interface should look like for all current and possibly future builders! It is split into 3 separate parts, denoted by the headings.
Before you answer, please read through the entire RFC, and don’t jump to answering just one question only. You don’t have to answer question 3 if you have nothing to add to it, but the other two would be super appreciated to receive answers to. Thanks for reading this, and now let’s get started~!
1. The interface
One of the key issue with the current builders is the lack of a consistent interface between the Application Command builders, the Message Component builders and the Embed builder.
As it stands at the time of writing this RFC:
- Application command builders follow a nested approach, with
.add*
methods for each option type. The class’s fields represent the structure similar to how the api payload will look like. - Message component builders follow part of the same structure as application command builders, with some caveats (
addComponents
takes in any component, whereasadd*
in application command builders add just that one kind of options), some options that take in arrays allow rest parameters too (something that in my opinion is fine except forset*
methods that should take in an array only). The class stores all data in adata
property, and accesses it for setting/reading the properties in it - Embed builder also stores the actual api embed data in the
data
field. They also allow input incamelCase
format, where no other builder allows (or should allow) that.
Several things need to be decided:
- How should the classes store the data that will be returned from
toJSON()
calls? In adata
field or as the class fields themselves? - Should
addComponents
be removed in favor ofaddButton
,addSelectMenu
and so on? Or should application command builders useaddOption
instead? - Should nested objects in any builder be a raw object or should they be miniature builders? Consider EmbedBuilder#author. Currently it’s a raw object. Should it be brought in line with the other two builders and nest it as a builder?
My opinion on those 3 questions are:
The class fields should represent as closely what the toJSON will return. CallingWell I changed my mind, we should instead use the{ ...builder }
should return the same valid data as callingbuilder.toJSON()
data
field, however no getters should be added pointing to said field- ActionRowComponent should use the same interface as application command builders (one
add*
per component type) - EmbedBuilder should get nested builders for such fields (with fallbacks allowed for objects for users if it’s gonna be such an issue).
2. The validation
Outside of application command builders, every other builder has 2 classes inside. An “Unsafe” class (which has 0 input validation) and a “Safe” class (which has validation for inputs (and quite fast validation at that)).
From my perspective, this split needs to be removed. The point of builders is to provide a consistent interface for creating api data. Creating two classes that achieve the same thing, even if one of them just extends the other, feels wrong and redundant. All builders should use validation by default¹. This would clean up a lot of the classes, and also remove the issue that other modules using builders need to export both safe and unsafe versions (the latter of which might scare users away).
¹: Validation should instead be able to be turned off at the validation library level (something that we have planned in shapeshift actually (work feedback that we agree would be a good addition)). That way, you can decide in your code if the validation should be turned on or off (for instance turn off validation automatically if in a production environment)
3. The pain points
This point is more less an open page for you to air out what frustrations you’ve encountered with the interface. For this, I’d prefer if you sticked to issues related more to consistency or type issues or performance worries (etc), and not the fact the interface has/will change again. The builders package is still not on version 1, meaning we’re still more-less in development to a degree.
Feel free to add anything that you think would improve the overall experience for everyone.
Issue Analytics
- State:
- Created a year ago
- Comments:10 (10 by maintainers)
Top GitHub Comments
I feel like these points contradict each other and ignore a lot of what I said in the first comment. The attitude towards component builders continues to be focused on building them for the first time, with no consideration for editing.
ButtonComponent.from(theData).setDisabled()
is not sufficient. How do you then replace that one button in what could be up to 5x5 rows?It should not be necessary to clone 5 action rows / 25 buttons using
Component.from
just to edit one nested item.Maybe you wouldn’t set all 5 - this is a better argument for
spliceComponents
, but still. Consider the editing usecase.If that’s a design decision to be made for component builders, then so be it, they can only build. However it should be acknowledged that this greatly undercuts their usefulness and ignores user stories that I personally would consider must-haves were this a product being designed based on the requirements of actual developers,