-
Notifications
You must be signed in to change notification settings - Fork 7
Code deduplication #138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Code deduplication #138
Conversation
… require() and used in multiple places
…ld've been from the beginning
…v files. And call to dotenv was after env vars vare used.
667421e to
d0de04d
Compare
|
I tested everything and it should work, but I ended up changing more stuff than I initially planned. |
p2r3
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few nitpicks and comments, but overall great job. Good code, and some much needed refactors.
I've only looked at the code for now, I'll approve and merge this once I've tested it.
common.js
Outdated
| .replaceAll("@everyone", "@everyone") | ||
| .replaceAll("@here", "@here"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be explicit, the zero-width space should probably be denoted with its escape sequence (\u200B), rather than pasted directly into the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nitpick: added lines are missing semicolons.
pages/profile/main.js
Outdated
| }; | ||
|
|
||
| } | ||
| const whoami = await handleWhoami() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nitpick: missing semicolon.
routines/live.js
Outdated
| // Announce the beginning of COTD on Discord | ||
| // HACK: Hardcoded role ID for now, must fix ASAP!!! | ||
| await discord(["live", `<@&1363135650572009523> The [Chamber Of The Day](<https://epochtal.p2r3.com/live>) is starting!\n${mapString}`], context); | ||
| await discord(["live", `${CONFIG.DISCORD.ROLE.COTD}The [Chamber Of The Day](<https://epochtal.p2r3.com/live>) is starting!\n${mapString}`], context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space between role ping and text?
On a tangentially related note, it's not immediately clear that config ROLEs hold ping-formatted strings. Before checking, I assumed it just held the role ID, and so thought this was a mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that ping might be @everyone, which doesn't follow the same <@&...> pattern. Now I see my approach having some flaws. But I'm not sure what would be the solution. Storing just the id in CONFIG.DISCORD.ROLE.COTD and CONFIG.DISCORD.ROLE.COTD ? "<@&" + CONFIG.DISCORD.ROLE.COTD ">" : "@everyone"? But that would move the default value from config.ts. Or maybe rename it to, let's say, PING instead of ROLE and keep it in <@&...> format? But then should the envvar hold just ID or ping-formatted string?
The space, though, is missing. I was literally thinking about not missing the space and missed the space.
soni801
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot to say. First of all, great job on this. as p2r3 mentioned, this pr does many long-needed code optimizations. However, even though it's a great starting point, theres still quite a bit of nitpicks/changes that would make sense to make when you're restructuring like this in the first place.
I've made a few commends on individual files and lines, but I also have a few comments to add overall:
- I don't necessarily like that
/pages/shared.jsis used in the backend. Yes, I know that the point is to deduplicate code, and it works well for that purpose, but the file location implies that it's only used in the frontend.- The file should be placed further up in the file tree, but I don't know if there is a good way to solve this though, given that web clients need access to this file. Try to look into mapping files from outside the webserver root dir into a servable file locator?
- Honestly it doesn't matter that much, and it's fine to be left like this, but again when the PR is all about improving code structure I feel like this is an important point to take into account.
Unrelated to the actual changes, I'll also make some comments on your version control:
- Generally great commit naming. Thank you :D
- Many of your commit titles are too long however, causing them to be hard-wrapped into the commit body. Best practice is considered to keep commit titles <50 characters. (I'll add this to the contribution guidelines at some point, don't worry)
- If you do feel like you want more context, write a short title and explain context in the commit body yourself, to avoid the hard-wrapping :)
I'm honestly gonna say I'm too lazy to test this, mostly because of the enourmous scope of changes this PR does. Just to confirm, you've tested that every feature this PR touched is working as before?
I'll wait for @p2r3 to test these changes, and then I might do some minor tweaks of my own, before ultimately merging.
I'm also gonna add these for Github to auto-associate this PR to issues:
| @@ -0,0 +1,35 @@ | |||
| /** | |||
| * Requests a bunch of stuff for the ui to render and initializes WebSocket connection | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"a bunch of stuff" is way too vague for the comment to really be necessary. It should either
a) specify what it actually requests
b) rewrite the comment to exclude that part and describe what the function does in a different way.
Where i see A to be the best option.
| const leaderboard = await (await fetch("/api/leaderboard/get")).json(); | ||
| const config = await (await fetch("/api/config/get")).json(); | ||
| const users = await (await fetch("/api/users/get")).json(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a pretty compact way to write this, and it kinda makes sense. However, double await looks very unclean and makes it take longer to read and properly understand what the code does.
I would suggest splitting the two await's into different steps, clearly outlining what every step does. This does come at the cost of slightly higher overhead (declaring intermediate varialbes), but that difference in overhead will be so small that it'll never be noticable in actual execution. For me, that is a completely acceptable tradeoff for more readable code. @p2r3 thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure this is how it's done in base Epochtal code, likely not Myshy's idea.
I think it's readable enough, so to me the main drawback is the lack of support for cleaner error handling I suppose. But we're not doing error handling for this anyway! 😂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh sure, i mean its not the end of the world by any stretch of the imagination, but again, the scope of this PR includes making the code more readable. There is no real-world drawback of splitting these awaits other than the 2 minutes it takes to write.
It just seems like a missed opportunity to me to leave it as this.
| * Sends WebSocket events to the stream controller event topic, which the UI, game, and controller listen to | ||
| * @param {unknown} data Data to send, converted to a JSON string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worlds tiniest nitpick lmao, but we usually add an empty comment line between these two lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replacing VOTING_MAPS_COUNT with CONFIG.VOTING_MAPS_COUNT several times in this file is kind of a regression in my mind. VOTING_MAPS_COUNT should still be defined inline and be referred to as it originally was, however, instead of being initialized to 5, it should be set to CONFIG.VOTING_MAPS_COUNT.
Referring to a local variable that then refers to some global config makes it easier to locally overwrite the variable if that is needed for some reason at some point, and adds negligible overhead.
Generally this is just the mindset that the more abstraction/references, the better (to a certain extent of course). Define once, but for every "level deep", allow to overwrite said definitions for all underlying usages.
...I feel like i explained that in a horrible way. Does that make sense?
| if (!(cat in profile.statistics)) profile.statistics[cat] = []; | ||
| if (!(cat in profile.weeks)) profile.weeks[cat] = []; | ||
|
|
||
| profile.statistics[cat].push(catDeltaElo[cat][steamid]); | ||
|
|
||
| profile.weeks[cat].push(weekNumber); | ||
| if (!profile.weeks.total.includes(weekNumber)) { | ||
| profile.weeks.total.push(weekNumber); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am kind of missing just a few small comments here explaining the code flow.
Don't get me wrong, this is simple code, but i wanna be able to see how it works without needing to read it. Again, just a tiny nitpick to slightly aid developer experience.
| // Return the raw data if requested | ||
| if (raw) return details; | ||
| // Return the raw data if requested or return error | ||
| if (raw || typeof details === "string") return details; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we checking if it is a string? (should be clearly described in the comment)
| # This defines how far back in time the curation algorithm fetches maps from. | ||
| # If left unset, defaults to 604800 (one week) | ||
| #CURATE_SECONDS= | ||
| #The amount of maps in the voting pool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super duper extremely tiny nitpick: add leading space here lol
| ROLE: { | ||
| /** | ||
| * The ID of the Discord role to ping for announcements | ||
| */ | ||
| ANNOUNCE: process.env.DISCORD_ROLE_ANNOUNCE ? "<@&" + process.env.DISCORD_ROLE_ANNOUNCE + ">" : "@everyone", | ||
| /** | ||
| * The ID of the Discord role to ping for Chamber Of The Day | ||
| */ | ||
| COTD: process.env.DISCORD_ROLE_COTD ? "<@&" + process.env.DISCORD_ROLE_COTD + ">" : "@everyone" | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not a fan of this. config.ts serves the role of aggregating configuration options and providing defaults, not data processing.
I understand what you're trying to achieve here, but this is not the place to process/modify the input string (principle of separation and modules keeping to one task). The way I would solve this is to define some type of globally available function that transforms a role ID into a pingable role, or substitute it with @everyone if the input is empty/null/undefined. I think discordjs even has a builtin function for this?
| /** | ||
| * When the Chamber Of The Day should be released | ||
| */ | ||
| COTD_CRON: process.env.COTD_CRON ?? "0 0 19 * * 6", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nitpick: we don't traditionally use trailing commas in objects, but this isn't really an established code style. @p2r3 thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the code style is to be based entirely on my preferences as the author or whatever, then yes. I don't use trailing commas in JS.
Move duplicated functions into their own files, so they are declared once and can be
require()d and used in multiple places.I tested it and pretty sure it works fine, but I still need to make sure I didn't break anything. Also I think I missed some duplicated code. Any ideas of how to further improve the codebase in this direction are welcome.
Fixes #51, #133 #132