Description
Now that we have some tracking on this repository, I'd like your input on going forward.
Current architecture
The initial architecture is mostly matching the ruby-analyzer
, which means it's currently using exceptions as control flow. I'm personally not a fan, but for the use-case it works quite well. The interface API is extremely small:
approve
: instantly mark as approveddissapprove
: instantly mark as dissapprovedredirect
: instantly mark as "need human eyes"comment
: add a comment
I think it's also better than a pure functional approach as follows, because the example below quickly becomes as cognitively complex as the exception flow as soon as you need to nest rules, with the added bonus that if you forget a return, everything breaks (but might not actually error the program):
function execute(program) {
if (!hasNamedExport(program)) {
return new Output('dissapprove', { comments: [CommentFactory['named-export']] })
}
if (anotherCheck(program)) {
if (!nestedRequiredment(program)) {
return new Output('dissapprove', { comments: [CommentFactory['nesting']] })
}
if (isMinimal(program)) {
return new Output('approve', { comments: [CommentFactory['tip-remove-nesting']] })
}
}
...
}
I do like the way the comment system is set up. It will give reasonable types which actually work, as soon as you give it one parameter (doesn't work with 0 parameters, yet). basically this is supposed to make sure the comments work even when they are extracted to the website-copy repo.
Work in progress
I have started extracting functions from the logic. These composable parts should help you write analyzers. They can do things like, but not limited to:
- find top level constants
- find the first node of a certain type
- find a member call
- check if token is a template literal
Additionally I've started on functionality where we can output equivalent code but change the output. The reason for this is we might want to give back alternatives using the solution's code without having to search for it (using location parameters, which can be buggy). For example you can fetch the parameter name of a function, and re-use that in the comments.
Preferable alternative?
The csharp-analyzer
has a nice approach where:
- each exercise gets its own
ExerciseSolution
class which is constructed with theProgram
; - properties of the program are defined on the
ExerciseSolution
so the "properties" live in one place - each exercise gets its own ExerciseAnalyzer` class (same as Ruby, JavaScript, TypeScript)
- the analyzer has the flow and logic of which properties lead to which commentary.
This would basically be what we currently have, but refactor out solution properties from the logic. This would also remove most if not all "instance variables" from the analyzer (which I think is a win).
What's the gist?
Personally I would like to keep two-fer
as is, but try out new patterns when tackling #13 and #14. Your thoughts and ideas are highly appreciated!