Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[proofing] Fully clean up search/replace UX #499

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

akprasad
Copy link
Contributor

@akprasad akprasad commented Apr 5, 2023

These changes build on @kvchitrapu's prior work and simplify it slightly.

Specifically, this makes the following changes:

  • collapse the UX from 4 phases (search, check, confirm, submit) to 3 (search, check, submit) -- I felt that the "confirm" stage was not adding much as compared to the complexity it added.
  • create a single _find_replacements utility function that does the regex searching, etc. By using dataclasses, we can reuse this one function for the full flow.
  • add unit tests to increase test coverage

Proposed flow:

image

image

image

image

@akprasad akprasad requested a review from kvchitrapu April 5, 2023 03:41
@akprasad
Copy link
Contributor Author

akprasad commented Apr 5, 2023

@kvchitrapu I made some substantial changes here so that the UX cleanup could go a little smoothly. I think this preserves your original vision but I'm curious what you think of the new changes.

Edit -- I should also mention that I love the logging but that I found it very difficult to read the code with them. Would love to find a balance between logging and keeping the code readable.

Copy link
Collaborator

@kvchitrapu kvchitrapu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer personally reviewing changes to ensure accuracy. By conducting double-checks, we give proofers ample opportunities to thoroughly review their work, especially when dealing with large batches of changes.

In my opinion, relying solely on results without validation could potentially lead to errors. For instance, I do not simply run a "search-replace" all in an editor when renaming a variable. Instead, I go through each line to ensure precision.

However, I do recognize the convenience that this new approach offers. I am open to either method, as long as we are aware of the trade-offs involved.

},
)
assert resp.status_code == 200
assert "Found 12 matching lines for query" in resp.text
Copy link
Collaborator

@kvchitrapu kvchitrapu Apr 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good work! We now have test data to validate these changes.

@@ -391,216 +413,98 @@ def replace(slug):
if project_ is None:
abort(404)

form = ReplaceForm(request.form)
form = ReplaceForm(request.args)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is request.args your preferred way to pass params to the server? After experimenting a bit, I came out in favor of form. At some point args will break as the query or replace string grows in size or perhaps has sensitive info or has data unsupported in the url. Perhaps I'm missing your reasoning here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for most cases, query and replace will be small. For small form submits where the information is not sensitive and where there is no database state change, GET with request.args is the common pattern.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You see

Thanks for the review!

For instance, I do not simply run a "search-replace" all in an editor when renaming a variable. Instead, I go through each line to ensure precision.

I agree that a blind search/replace is unwise and that the user must review each change to ensure quality. My feeling is that the phase where the user checks/unchecks each item in the result set accomplishes this purpose already. I'm curious why you feel differently.

In my opinion, it's easy to verify the checks/unchecks when there are only a handful of matches on a single search+replace page. However, as the number of matches increases (for example, hundreds of matches), the pagination will spread the checks/unchecks across multiple search+replace pages. This can make it difficult to keep track of which checks/unchecks have already been applied, leading to potential tracking issues.

Copy link
Collaborator

@kvchitrapu kvchitrapu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Replacement class is a good idea. I think we may have to refine the replacement logic further.

def marked_replace(self) -> str:
buf = []
for i, t in enumerate(self.splits):
if i % 2 == 1:
Copy link
Collaborator

@kvchitrapu kvchitrapu Apr 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This odd/even heuristic may not always work. I believe what you are saying is query is a delimiter and the resulting splits will always have regex matched elements in odd indices. The regex will escape the odd/even structure. If you want to go ahead, put an assert that odd index matches the query/regex pattern.

Also, this is one reason it is best to review/confirm the changes before committing. The confirm page will be a nano-version of what PR is for software.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add an assert. This is an invariant guaranteed by the Python standard library:

If there are capturing groups in the separator and it matches at the start of the string, the result will start with an empty string. [...] That way, separator components are always found at the same relative indices within the result list.

(emphasis added)

@akprasad
Copy link
Contributor Author

akprasad commented Apr 8, 2023

Thanks for the review!

For instance, I do not simply run a "search-replace" all in an editor when renaming a variable. Instead, I go through each line to ensure precision.

I agree that a blind search/replace is unwise and that the user must review each change to ensure quality. My feeling is that the phase where the user checks/unchecks each item in the result set accomplishes this purpose already. I'm curious why you feel differently.

@kvchitrapu
Copy link
Collaborator

kvchitrapu commented Apr 16, 2023

Sorry @akprasad . I intended to get back to my regular routine last week, but I couldn't find time to unblock my schedule. I'll get back on track this week.

@kvchitrapu
Copy link
Collaborator

@akprasad , go forward with this PR and land it. Consider adding an assert to catch lines that escape odd/even structure. Record user's regex in the log message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants