I find the comment at the end interesting // Creates a user and returns the newly created user's id on success Hmm, it returns an id? But the @returns is Promise ? 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 , making t…
Self-Documenting Code
41–50 of 131 posts
Re: Self-Documenting Code
#42Code only tells you 'what,' not 'why.' And 'why' is usually what matters.
(I do generally agree with your point.)
Re: Self-Documenting Code
#43Re: Self-Documenting Code
#44My cut: const passwordRules = [/[a-z]{1,}/, /[A-Z]{1,}/, /[0-9]{1,}/, /\W{1,}/]; async function createUser(user) { const isUserValid = validateUserInput(user); const isPasswordValid = user.password.length >= 8 && passwordRules.every((rule) => rule.test(user.password)); if (!isUserValid) { throw new Error(ErrorCodes.USER_VALIDATION_FAILED); } if (!isPasswordValid) { throw new Error(ErrorCodes.INVALID_PASSWORD); } cons…
My only nitpick is that the const isPasswordValid = ... should be just before its use (between the first two ifs). Other than that, I prefer this approach (although I would inline the booleans in the ifs to avoid the one-use variables. But that's ok). > Don't use a bunch of tiny functions Exactly this. I only do that when the function is used in more than 10 places and it provides some extra clarity (like something a…
Wouldn’t that cause the regexes to be recompiled every time you call the function?
Re: Self-Documenting Code
#45My cut: const passwordRules = [/[a-z]{1,}/, /[A-Z]{1,}/, /[0-9]{1,}/, /\W{1,}/]; async function createUser(user) { const isUserValid = validateUserInput(user); const isPasswordValid = user.password.length >= 8 && passwordRules.every((rule) => rule.test(user.password)); if (!isUserValid) { throw new Error(ErrorCodes.USER_VALIDATION_FAILED); } if (!isPasswordValid) { throw new Error(ErrorCodes.INVALID_PASSWORD); } cons…
This is where the naming things bit comes in. You name the function correctly, then when the body is read to understand that it works as named, you can remove that cognitive complexity from your brain and continue on. Once you’ve built trust in the codebase that things do what they claim, you can start getting a top-down view of what the code does.
That is the power of proper abstraction.
Re: Self-Documenting Code
#46My cut: const passwordRules = [/[a-z]{1,}/, /[A-Z]{1,}/, /[0-9]{1,}/, /\W{1,}/]; async function createUser(user) { const isUserValid = validateUserInput(user); const isPasswordValid = user.password.length >= 8 && passwordRules.every((rule) => rule.test(user.password)); if (!isUserValid) { throw new Error(ErrorCodes.USER_VALIDATION_FAILED); } if (!isPasswordValid) { throw new Error(ErrorCodes.INVALID_PASSWORD); } cons…
Then, in general (not seen here as there are no types), I like to use a lot of types in my code. The incoming user would be of type UnvalidatedUser, whereas the return type of this function would be StoredUser or something like that to distinguish the incoming user type with the outgoing. I like to attach semantics to a type, not to conditions: https://existentialtype.wordpress.com/2011/03/15/boolean-bli...
Re: Self-Documenting Code
#47Re: Self-Documenting Code
#48Earlier quoted context omitted.
I would go further to say that syntax should never be used. for example with Go: > cheapFunction(...) || expensiveFunction(...) is not valid unless both functions return bool > car = car || "bmw" is not valid at all, because both types would need to be bool > funcA(...) && funcB_WhichMightBreakWithoutFuncA(...) not valid unless functions return bool. I think Go smartly realized this syntax is just sugar that causes m…
This has nothing to do with syntax and short circuiting and everything to do with Go's type system. Go, like most compiled languages, has no concept of "truthiness". JavaScript is not Go and has truthiness. We can debate the merits of truthiness and using it this way, but let's have that debate on the merits, not by invoking other languages with completely different design constraints. Your argument here is similar t…
Re: Self-Documenting Code
#49Earlier quoted context omitted.
My only nitpick is that the const isPasswordValid = ... should be just before its use (between the first two ifs). Other than that, I prefer this approach (although I would inline the booleans in the ifs to avoid the one-use variables. But that's ok). > Don't use a bunch of tiny functions Exactly this. I only do that when the function is used in more than 10 places and it provides some extra clarity (like something a…
> My only nitpick is that the const isPasswordValid = ... should be just before its use (between the first two ifs). Wouldn’t that cause the regexes to be recompiled every time you call the function?
const isUserValid = ...
if(!isUserValid) ...
const isPasswordValid = ...
if(!isPasswordValid) ...
EtcRe: Self-Documenting Code
#50Earlier quoted context omitted.
This has nothing to do with syntax and short circuiting and everything to do with Go's type system. Go, like most compiled languages, has no concept of "truthiness". JavaScript is not Go and has truthiness. We can debate the merits of truthiness and using it this way, but let's have that debate on the merits, not by invoking other languages with completely different design constraints. Your argument here is similar t…
just because a footgun exists, doesn't mean you should use it
"Because Go doesn't support it" would also be a reason to avoid:
* Generics (at least until recently)
* Classes
* Prototypes
* Exceptions
* Async/Await
* Package managers (until recently)
* Algebraic data types
* Effect types
* Type inference
* Type classes
* Etc.
You could argue that one or more of these are footguns, but I seriously doubt you'd consider them all to be, so let's talk about what separates the footgun from the feature that just didn't fit in Go's design.