I followed the testing instructions and everything look’s good 😁
Below is a detailed checklist of what I went through.
- [ ] Pull Request: The PR template was fully filled out.
- [ ] Clear description of the problem and how it was solved.
- [ ] I’ve cross-checked the description with the associated Jira ticket; and everything is implemented.
- [ ] I’ve ticked-off the PR’s check-boxes.
- [ ] Good use of bullet points (-) and code font (‵, ‷) to make the prose easier to read.
- [ ] The commit messages are well-written.
- [ ] Travis CI succeeds.
- [ ] PR author annotated source code, with Github comments, before the review.
- Annotations guide the reviewer through the changes, showing which files to look at first and defending the reason behind each code modification.
- [ ] Functionality: The code behaves as the author intended.
- [ ] I was able to reproduce the bug on
main. - [ ] Ran the code and used it as an end-user would.
Namely, I made a new form, submitted an instance, checked
In-Progress, &Form Reports. - [ ] I’ve tried all kinds of quotes and unicode, “𝒰”\‘ℕ’/𝒊′ℭ″𝑂؛𝒟⨾’∃’, input for text inputs; as well as special chars: +-_)(*&^%$#@!~`’”.;><?/}{}[]|.
- [ ] Followed the happy path in the provided testing instructions.
- Nope; none provided.
- [ ] Also tried the following edge case: ⋯ ⁉ ⋯
- [ ] I was able to reproduce the bug on
- [ ] Tests: There are new unit tests (but sadly no E2Es/integration).
- [ ] Meaningful: Tests actually test that the code is performing the intended functionality.
- [ ] Ran associated E2Es / unit tests with the incantation: ⋯ ⁉ ⋯.
- [ ] I looked at the associated migrations file and ran the following SQL
query after running migrations and it works fine; then I ran the query
after running rollbacks and everything is as expected.
??? - [ ] Avoid global test fixtures and seeds, add data per-test. TL;DR: To prevent test coupling and easily reason about the test flow, each test should add and act on its own set of DB rows.
- [ ] Naming: Clear and informative names were chosen for top-level-items/variables/methods.
- [ ] Comments: New top-level-items/variables/methods have clear and useful
documentation.
- [ ] Sometimes the code is clear —e.g., 5 lines perform a toggle—
but we can improve readability by providing a “comment as function”
—e.g., making a
togglefunction, then calling it where it is used; this new function is likely to be smaller than the original inlined use.Some comments-as-functions have been suggested.
- [ ] Sometimes the code is clear —e.g., 5 lines perform a toggle—
but we can improve readability by providing a “comment as function”
—e.g., making a
- [ ] Being Neighbourly: There was nearby code that could have been
improved/update, and suggestions have been left as to how to do so.
- We’re likely to touch these files again in the future, so why not leave things better than we found them 🚀
- [ ] Code Smells: Are there any code smells?
- [ ] Syntax: I’ve read every line.
- Nope, there was some stuff I’m not familair with. If the PR authour can jump on a call and walk me through them, that’d be awesome!
- [ ] I’ve left various suggestions and feedback, against specific lines of code. Happy to discuss these further!
- [ ] I took my time while reviewing your code, and I’m not depending on others to catch errors.
- [ ] Complexity: Another developer can easily understand and use this code when they come across it in the future :-)
- [ ] Modulairty: Is there any redundant or duplicate code? Is the code as modular as possible?
- [ ] Backwards Compatiable: I made a form in
main, involving the work in this branch, and it worked fine in this branch.- I was able to edit the form, submit it, and checked that it looked find in
Form Reports.
- I was able to edit the form, submit it, and checked that it looked find in
- [ ] Best Practices: The following rules-of-thumb are adhered to, more or less.
Details
- Remove some redundancy using a bit of laws of algorithmics, namely
[𝒆𝒕𝒂-𝒓𝒆𝒅𝒖𝒄𝒕𝒊𝒐𝒏] ⋯(x => f(x))⋯ ≡ ⋯f⋯[𝒊𝒇-𝒅𝒊𝒔𝒕𝒓𝒊𝒃𝒖𝒕𝒊𝒗𝒊𝒕𝒚] (a ? f(b) : f(c)) ≡ f(a ? b : c)
which increase readability a tad.
- Fail fast, validate arguments [we have some in-house validation util libraries]
- Be aware that
0, "", []are all falsey values in JS: If a variablexcan be one of those things, thenif (x)is not always approriate; better may beif(typeof x === 'integer')since this communicates two things (1) the variable is defined, and (2) what it’s type expected is.- Likewise, better use
typeofinstead ofx !== null.
- Likewise, better use
- You have variables declared a bit from their use sites; the distance creates an unnecessary disconnect —especially since you don’t use these variables elsewhere. Please relocate them to be closer to their use sites.
- Strings are sanitised
- Errors are caught; with
try/catch - Global variables are avoided, when possible.
constis preferred tolet;varshould seldom be used.- Use
varandfunctionwhen you want definitions hoisted to the top of their enclosing scope.
- Use
===is preferred to==.- Use default arguments instead of short-circuiting or conditionals
f (x) { x = x || defaultValue; ⋯ }≡f (x = defaultValue) { ⋯ }.- Named parameters can also be optional, with default values:
f(obj) { let prop = obj.prop || defaultProp; ⋯}≣f ({prop = defaultProp}) { ⋯ }
- Unless you really need an array, handled an indefinite number of
arguments using rest parameters:
function f(...args) {⋯ // use ‘args’ as an array}can be invokedf(x₁, x₂, …)without array brackets; or asf(...arr)if you have an array in-hand. - Function arguments: 3 or fewer ideally
- If you need to declare an argument but are not using it, prefix it’s name with an underscore.
- Encapsulate conditionals in a separate well-named function, if possible
- Avoid negative conditionals; e.g., by making use of well-choosen names.
- Use Demorgan’s rules:
!x && !y ≣ !(x || y)and!x || !y ≣ !(x && y). - Use
try/catchwithasync/await; or promises with boththenandcatch. - Don’t ignore rejected promises, log it to external logging service
- Related chunks of code are clearly demarcated.
- If an anonymous function is too long, more than 2 lines, give it a name:
E.g., in JS,
arr.map(x => ...) ≣ arr.map( function doingSomeComplexStuff(x) { return ...} ). The name aids in communicating the intent, and is useful for debugging. - [ES6] Braces are used for block scope, and not simulated using IIFEs.
- Avoid explicit newlines with
+ "\n" +in-favour of Template Literals, which preserve line breaks. - Use Destructuring instead of explicit projections; aids in readability.
- Note∶
let y = x.y≡let {y} = xonly holds whenxis notnull(and so whenxis not a expression involving?.).
- Note∶
- Remove some redundancy using a bit of laws of algorithmics, namely