3 Refactoring Rules and Suites🔗ℹ
Resyntax derives its suggestions from refactoring rules, which can be grouped into a
refactoring suite. Resyntax ships with a default refactoring suite consisting of many rules
that cover various scenarios related to Racket’s standard libraries. However, you may also define your
own refactoring suite and rules using the forms below. Knowledge of Racket macros, and of
syntax-parse in particular, is especially useful for understanding how to create effective
refactoring rules.
(define-refactoring-rule id | #:description description | parse-option ... | syntax-pattern | pattern-directive ... | template) |
|
|
|
Defines a
refactoring rule named
id. Refactoring rules are defined in terms of
syntax-parse. The rule matches syntax objects that match
syntax-pattern, and
template is a
syntax template that defines what the matched code is refactored
into. The message in
description is presented to the user when Resyntax makes a suggestion
based on the rule. Refactoring rules function roughly like macros defined with
define-syntax-parse-rule. For example, here is a simple rule that flattens nested
or expressions:
Example:
Like syntax-parse and define-syntax-parse-rule,
pattern directives can be used to aid in
defining rules. Here is a rule that uses the #:when directive to only refactor or
expressions that have a duplicate condition:
Example:
(define-refactoring-suite id rules-list suites-list)
|
|
rules-list | | = | | | | | | | | #:rules (rule ...) | | | | | | suites-list | | = | | | | | | | | #:suites (suite ...) |
|
|
|
Defines a
refactoring suite named
id containing each listed
rule.
Additionally, each
suite provided has its rules added to the newly defined suite.
Example:
3.1 Resyntax’s Default Rules🔗ℹ
The refactoring suite containing all of Resyntax’s default refactoring rules. These rules are further
broken up into subsuites, with each subsuite corresponding to a module within the
resyntax/default-recommendations collection. For example, all of Resyntax’s rules
related to
for loops are located in the
resyntax/default-recommendations/for-loop-shortcuts module. See
this directory for all of Resyntax’s default
refactoring rules.
3.2 What Makes a Good Refactoring Rule?🔗ℹ
If you’d like to add a new refactoring rule to Resyntax, there are a few guidelines to keep in
mind:
Refactoring rules should be safe. Resyntax shouldn’t break users’ code, and it shouldn’t
require careful review to determine whether a suggestion from Resyntax is safe to apply. It’s better
for a rule to never make suggestions than to occasionally make broken suggestions.
Refactoring rules can be shown to many different developers in a wide variety of different
contexts. Therefore, it’s important that Resyntax’s default recommendations have some degree of
consensus among the Racket community. Highly divisive suggestions that many developers
disagree with are not a good fit for Resyntax. Discussing your rule with the Racket community prior
to developing it is encouraged, especially if it’s likely to affect a lot of code. If necessary,
consider narrowing the focus of your rule to just the cases that everybody agrees are clear
improvements.
Refactoring rules should explain themselves. The description of a refactoring rule (as
specified with the #:description option) should state why the new code is an improvement
over the old code. Refactoring rule descriptions are shown to Resyntax users at the command line, in
GitHub pull request review comments, and in Git commit messages. The description is the only means
you have of explaining to a potentially confused stranger why Resyntax wants to change their code,
so make sure you use it!
Refactoring rules should focus on cleaning up real-world code. A refactoring rule that
suggests improvements to hypothetical code that no human would write in the first place is not
useful. Try to find examples of code "in the wild" that the rule would improve. The best candidates
for new rules tend to be rules that help Racketeers clean up and migrate old Scheme code that
doesn’t take advantage of Racket’s unique features and extensive standard library.
Refactoring rules should try to preserve the intended behavior of the refactored code,
but not necessarily the actual behavior. For instance, a rule that changes how code handles
some edge case is acceptable if the original behavior of the code was likely confusing or surprising
to the developer who wrote it. This is a judgment call that requires understanding what the original
code communicates clearly and what it doesn’t. A rule’s #:description is an excellent place
to draw attention to potentially surprising behavior changes.
Refactoring rules should be self-contained, meaning they can operate locally on a single
expression. Refactoring rules that require whole-program analysis are not a good fit for Resyntax,
nor are rules that require global knowledge of the whole codebase.