DEV Community

Discussion on: Writing a code analyzer in TypeScript (from scratch)

Collapse
 
jsjoeio profile image
Joe Previte (he/him)

I like that in your solution you say "Optimal is extracting the GIGASECOND_IN_MS value as a top-level constant".

I did not do this in my solution, but I can see how it makes your code more readable. I also like how you defined your variable name in all caps.

What's your personal rule of them for this? (i.e. when to use all caps)

Collapse
 
sleeplessbyte profile image
Derk-Jan Karrenbeld

Great questions!

I am actually writing the analyser code to approve_with_comment if someone has not extracted it. There are two variants we see that are approvable but not optimal.

// Variation one
export function gigasecond(...) {
 const gigasecond = 10 ** 12
 return ...
}

They already have it as a constant, but it's "re-created" each invocation. Extracting is might be a premature optimisation from a speed standpoint, but that's not it.

  1. The variable name is shadowing the function name, which leads to subtle bugs.

  2. Extracting the constant to the top-level allows for re-use (which is ok, not a necessity)

  3. Extracting the constant is declaring intent: this is a "compile"-time value, that is actually constant in value, and not just assignment, which is further solidified with making it UPPERCASE

In the above case, extracting it is a small gain, but mostly for declaring intent.

// Variation two
export function gigasecond(...) {
 return new Date(... + 10 ** 12)
}

There is nothing wrong with the solution above, but this is a magic number or rather magic expression. It's adding a number to date, but in a year's time, can you remember why it's 10 ** 12 and not 10 ** 9 (which would be giga)? Maintainability is easier if you name your constants.

What's your personal rule of them for this? (i.e. when to use all caps)

This is just a preference I inherited from other languages where this is enforced in the language (Ruby constants start with a Capital for example), but mostly I do this in JavaScript and TypeScript based on:

  • If the constant is constant per invocation, e.g. it is a computed constant that can change based on the state of the process or function (input is a state), then I use const camelCase.
  • If the constant is constant per process, e.g. it is the same value when "compiled" or when "first interpreted", it is probably a file-level (and thus process-level) constant. I use const UPPER_CASE

The added benefit of the approach above is:

  • It's instantly clear which VALUE is always the same and which functionValue depend on state.
  • Most code highlighters (such as prism, or the tsc in vscode etc.) will color the UPPER_CASE differently.

I hope these make sense!

Collapse
 
jsjoeio profile image
Joe Previte (he/him)

They already have it as a constant, but it's "re-created" each invocation.

Great point! Didn't even think about that when I first wrote my solution.

Also, thanks for the detailed explanation and sharing your thoughts on when to use uppercase for your consts. Seems like a solid rule I may adopt into my own practice!

Collapse
 
jsjoeio profile image
Joe Previte (he/him)

Really interesting read! When I heard exercism was going to automate solutions, I didn't realize this is what they meant. I thought there was an "easier" way. But it's really fascinating to read about AST parsing.

The way you broke everything down made it feel more approachable than I originally thought. Thanks for sharing this and putting in all the work for the JS/TS communities.

Collapse
 
sleeplessbyte profile image
Derk-Jan Karrenbeld

C# has a different approach for two-fer and Ruby is going to try it out for another solution where they don't do AST interpretation like I do, but do AST matching:

  • parse the AST for a lot of solutions
  • strip the Identifier names and rename them to be consistent e.g. a, b, c or input_arg_1, body_constant_1 (so that two solutions that are identical except for the name use are now actually identical). This is normalisation
  • match the incoming, normalised AST of the solution to the set of known solutions, and have a fixed output.
  • periodically collect everything that is not matched and add these to the analyser.

I think that is an easier approach, but not necessarily a better one. Especially in JavaScript where you have so many ways to write the same thing (this each way creating a new set of permutations).

The way you broke everything down made it feel more approachable than I originally thought.

Feel free to contribute! 💘