We also made a small scratchpad you can use to test collaboration features, if it doesn't get too flooded :) https://docs.numerique.gouv.fr/docs/a3f0becc-f2b7-45be-a5e5-...
I found something I would qualify as a bug: if you click on the right of any text, the cursor is placed at the beginning of the line, where I would expect to have it at the end.
The Swords and Ravens blog post recommends resolving actions on the client when they don't require secret information, but resolving other actions on the server. You'd also need to resolve actions on the server when they involve RNG.
This design makes it easy to implement optimistic updates, rollback, replays, automated testing, and recovery after a disconnection. It's a surprisingly good fit for UI, too; you can render simple games as a React component which takes the current State as one of its props.
However, a stream of context-free actions can be a really inconvenient representation for some games. The rules of a board game are often like the control flow of a computer program: you'll see branching, iteration, local variables, function calls, structured concurrency, and sometimes even race conditions and reentrancy. When you try to represent all of this logic as a State object, you're basically maintaining a snapshot of a "call stack" as plain data, and manually resuming that "program" whenever you handle an action. It doesn't seem ideal.
I've been sketching a board game engine which would represent the game logic as normal code instead. It seems promising, but it really needs a couple of language features which don't exist in the mainstream yet, like serialisation of suspended async functions.
Fresh tools and more choice is very welcome, thanks for your work!
// Creates a user and returns the newly created user's id on success
Hmm, it returns an id? But the @returns is Promise<any>? The code as written will change when userService.create changes... without the actual, human readable bit of prose, that potential code issue could be easily overlooked.
Of course, here the code could have a newtype for UserId and return Promise<UserId>, making the code better and then the prose is basically not needed (but please just write a docstring).
FWIW I would document that the `user` parameter is modified. And document the potential race condition between checking the existence of a user and creating a user, and maybe why it was chosen to be done in this order (kinda flimsy in this example). Which would probably lead me to designing around these issues.
Trying to only document via self-documenting code seems to always omit nuances.
/** Create a user and return the id, or throw an error with an appropriate code.
*
* user.password may be changed after this function is called.
*/
async function createUser(user: User): Promise<number> {
if (!validateUserInput(user)) {
throw new Error(err.userValidationFailed);
}
if (isPasswordValid(user.password)) {
// Check now if the user exists, so we can throw an error before hashing the password.
// Note: if a user is created in the short time between this check and the actual creation,
// there could be an unfriendly error
const userExists = !!(await userService.getUserByEmail(user.email));
if (userExists) {
throw new Error(err.userExists);
}
} else {
throw new Error(err.invalidPassword);
}
user.password = await hashPassword(user.password);
return userService.create(user);
}
RedHat's style guide is far more detailed and closer to a reference/explanation (i.e. going by Diátaxis definition).
Google's technical writing is shorter and closer to tutorial/how-to guide.
I recommend the Google's technical writing if you're a coder or a beginner. RedHat is for folks who already know they need this on first look.
Your answer is perfect, thank you!