Tagger Code Review
Would anyone be keen to code review Tagger? I'd like to git better 😄
https://github.com/Haxxer/FoundryVTT-Tagger
14 Replies
I'll see about giving you some feedback today 🙂
Thanks!
Some thoughts for you, gonna split these into several so they can be replied to:
Documentation
Recommend referring to these "objects" as "PlaceableObject" to be consistent with Foundry API terminology. https://foundryvtt.com/api/PlaceableObject.html
Object Oriented Code is a 👍
I would make
Tagger
a class with basically all static methods instead of an object. What you have works, it just "looks wierd."
E.g. how this might be useful:
Architecturally, you have 2 'concerns' here:
1. The handling of the actual tags on the documents
2. The patches to the existing UI elements
These don't interact with eachother much from what I can tell and I'd consider splitting them up into two different classes:
Pulling the 'config' stuff out into its own class would let you make methods inside that class which you then pass to renderFormApplication
and closeFormApplication
, overall wouldn't give you much but it's something to think about for structuring code. It also makes window.Tagger
less heavy.
You've got some patterns in here that I personally wouldn't do or recommend. Admittedly I don't really understand why I avoid these things, it's something that was drilled into me and I've never really questioned.
Mutating things tends to cause headaches, it's not generally a good practice to mutate the arguments passed to a function within that function.
So you're mutating the inObject
argument if it has a document
property.
This could cause you a headache if you did something like this down the line:
Instead, consider playing it safe like so:
(also recommend using const
until you can't)
(double checking that mutating function arguments is actually prone to this kind of headache)Yeah, this article goes more into that whole shitshow:
https://techblog.commercetools.com/mutating-objects-what-can-go-wrong-7b89d4b8b1ac
Medium
Mutating Objects: What Can Go Wrong?
We all know that mutating objects can lead to unwanted side effects, and can introduce hard to trace bugs, and make code hard to test. In…
Mutation has more implications in some UI frameworks (like react) than it does in Foundry, so you're probably fine here. Like I said this is something that's been driven into me and I don't fully understand why (I work in react-land).
There's a lot of _validateObjects being used which indicates that you don't trust your data is being stored right. Nothing wrong with that but it feels a bit unnecessary.
If I had to guess, this stems from how you're injecting the DOM into the forms. Since you're giving the contractually obgligated to point out that the "recommended best practice" for sharing an API from a module is by putting it on
input
a name
, the stored value on form save would be a string:
However, you're looking for an array, so you call _fixUpTags
on applicationClose to remedy this. That feels a little janky.
I've got two alternatives to consider:
A) Don't hook on closeFormApplication
, but instead on preUpdate<WhateverDocument>
. Inside the preUpdate hook you can mutate what's about to be saved to the document. This has the added benefit of happening whenever the document is saved, not necessarily on close.
Some info: https://foundryvtt.wiki/en/migrations/foundry-core-0_8_x#for-update-operations
B) Don't give the injected input a name
, and instead use some other identifier. Then in your closeFormApplication
, use the html
argument to manually grab the input's value, and call setTags
yourself.
A+ for all the helper methods you have in here and their documentation. Inspires me to actually document my own stuff (some day... maybe...).
I am game.modules.get('my-module').api
.
But tbh, this is just so much more usable. It's unlikely that anyone will have a name collision with you, yolo.
You should update your LICENSE to have your desired name instead of "Repository Owner".
Use of fieldset
to make your input stand out is neat. Looks solid.
single letter variables are evil
Alright @wasp that's all I got for you. This is a nice little module, neatly made.
My main takeaways for you are "I hope I leave you with a vague sense of dread regarding mutation because that's what my mentors instilled in me all those years ago."Thank you for all of the feedback!
As for the
_validateObjects
- it's mostly used on public facing functions such as setTags
, getTags
, etc, which relies on provided parameters. It serves two functions - to validate incoming data, and to format it into a way that I would like to process it
Ie, one object gets array-ified, and cast to its relevant document if not already a document
But you're right, I may be relying on it a bit too much
re: preUpdate<WhateverDocument>
- how can I know what the tags I am to be setting if I don't hook on the config close? How do you propose I access the html I injected?I think since you have a name on that field, the raw data will be on the update object in the hook
Good point
being more defensive isn't bad to be clear
esp on the public functions, that makes good sense, I thought this was entirely because of the hook shennanegins maybe
Nope! Just appropriated to ensure it's valid 😄 Unnecessary now that I think about it, since the TaggerConfig will be 100% foundry side
Damn, the code is so much cleaner now, thank you @calego !
@wasp gave LeaguePoints™ to @calego (#1 • 1146)
One more thing, more as a "FYI" than a suggestion.
You can get away with these since you're using
esmodules
in the manifest, but if this were using scripts
these would cause problems:
Remedy for that would be to move them into Tagger
like so:
without the safety of either esmodules or being a class member, you would be prone to namespace collisionsImplemented, thanks!