[webkit-reviews] review denied: [Bug 177993] Add UI for A/B testing on owned commits. : [Attachment 328791] Patch

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Fri Dec 15 00:58:13 PST 2017


Ryosuke Niwa <rniwa at webkit.org> has denied dewei_zhu at apple.com's request for
review:
Bug 177993: Add UI for A/B testing on owned commits.
https://bugs.webkit.org/show_bug.cgi?id=177993

Attachment 328791: Patch

https://bugs.webkit.org/attachment.cgi?id=328791&action=review




--- Comment #10 from Ryosuke Niwa <rniwa at webkit.org> ---
Comment on attachment 328791
  --> https://bugs.webkit.org/attachment.cgi?id=328791
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=328791&action=review

I think we need to split the changes to CommitLog and the addition of
IntermediateCommitSet into a separate patch to make this patch manageable.

> Websites/perf.webkit.org/ChangeLog:8
> +	   Customizable test group form should support specifying and A/B
testing owned commits.

You should add a high description of what you're adding & what you're changing.

> Websites/perf.webkit.org/ChangeLog:23
> +	   (CustomizableTestGroupForm):

You should really explain why you're replacing dictionaries with map.
In theory, there should be a change log description for each code change you're
making.

> Websites/perf.webkit.org/ChangeLog:61
> +	   (IntermediateCommitSet): In order to support owned commits, commit
set should support mutation as we may add/remove commits for a repository.
> +	   This variant of commit set supports remove/update commits for
repositories.

You should explain the difference between IntermediateCommitSet and
CustomCommitSet.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:3
> +    constructor(defaultValue, didUpdateValue, candidates)

This argument order seems backwards. It should take the list of candidates
first and then the default value.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:7
> +	   this._didUpdateValue = didUpdateValue;

Don't use a callback in new code. Use dispatchAction & listenToAction combo
instead.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:13
> +	   this._selectedItemValue = '';

Why isn't this initialized to null instead?

> Websites/perf.webkit.org/public/v3/components/combo-box.js:18
> +    _createCandidateList(candidates, keyword)

I would call "keyword" just "key".

> Websites/perf.webkit.org/public/v3/components/combo-box.js:22
> +	   const startsWithKeywordList = [];

"startsWithKeyword" list is an awkward name. How about
candidatesStartingWithKey?

> Websites/perf.webkit.org/public/v3/components/combo-box.js:23
> +	   const containsWithKeywordList = [];

candidatesContainingKey? contains with keyword doesn't make much sense as a
phrase.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:24
> +	   for (const candidate of candidates) {

You should add some sort of a cap so that we don't end up showing too many
results (might be slow to build a large DOM like that).

> Websites/perf.webkit.org/public/v3/components/combo-box.js:29
> +	       if (keyword &&
!candidateInLowerCase.includes(keyword.toLowerCase()))
> +		   continue;
> +
> +	       if (candidateInLowerCase.startsWith(keyword.toLowerCase()))

Instead of calling includes & startsWith and thereby searching each string
twice, just call indexOf.
If the result is -1, it doesn't contain the keyword. If it's 0, then it starts
with the keyword.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:38
> +	       item.addEventListener('mousedown', () => {

Why are you creating link and then manually attaching an event listener?
Just use link(candidate, () => ~).

> Websites/perf.webkit.org/public/v3/components/combo-box.js:43
> +	       this._elementByCandidateName.set(candidate, item);

Why do we need a map from the candidate to its item like this?
Since each candidate generates exactly one element in your design,
you can just create an array and use _currentCandidateIndex to access the right
element.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:73
> +	       if(event.key === 'Tab' || event.key === 'Enter') {

Nit: Need a space between if and (. Why tab? Why is that special?

> Websites/perf.webkit.org/public/v3/components/combo-box.js:95
> +	   if (!this._inputValue.length)

This function should check the value of _currentCandidateIndex.
If it's not null, then the user had already picked a candidate so there is no
need to do the work here.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:97
> +	   const matchingCandidates = this._candidates.filter((candidate) =>
candidate.toLowerCase().includes(this._inputValue.toLowerCase()));

Why don't we find the first two matching candidates instead of finding all of
them?

> Websites/perf.webkit.org/public/v3/components/combo-box.js:119
> +	   if (candidateElement) {
> +	       if (previousElement)
> +		   previousElement.className = null;
> +	       candidateElement.className = 'selected';

This should be a enqueueToRender call instead.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:130
> +	   textField.value = this._inputValue;

You shouldn't always re-set the input element's value like this.
That would reset the caret position each time, which would be annoying user
experience.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:140
> +	       <input id='text-field'/>

Don't use self-closing syntax in HTML5.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:153
> +	       }
> +	       ul:empty {

Please add a blank line between each CSS rule.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:161
> +		   padding-left: 0.3rem;
> +		   padding-right: 0.3rem;
> +		   padding-bottom: 0.2rem;

Use the short hand: padding: 0.1rem 0.3rem.
This would expand to padding-left/right: 0.3rem and padding-top/bottom: 0.1rem.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:168
> +		   margin-top: -0.1rem;

Use 0.1rem padding for top-bottom instead of using a negative margin like this.

> Websites/perf.webkit.org/public/v3/components/combo-box.js:185
> +	       li a:hover, a.selected {

You're missing li for the second selector.
li a:hover, a.selected expands to "li a:hover" and "a.selected", not "li
a.selected".

>
Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js:1
> +function ensureSetForMap(map, key) {

I don't think we need this helper. It's only used once.

>
Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js:2
3
> +	   for (const label in map)

Do: for (const label of map.keys()) instead. It's more canonical & descriptive
way of iterating over keys of a map.

>
Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js:7
4
> -	   this._renderCustomRevisionTableLazily.evaluate(this._commitSetMap,
this._isCustomized);
> +	   this._renderCustomRevisionTable(this._commitSetMap,
this._isCustomized);

This would force the reconstruction of table in each render call. That's not
okay.

>
Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js:1
18
> +	       const ownsCommits = [...commitSetMap.values()].map((commitSet)
=> commitSet.ownsCommitsForRepository(repository)).every((value) => value);

Why isn't this just a call to every? map(f).every((x) => x) is equivalent to
every(f).

>
Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js:1
25
> +		   const lastRow = index === ownedRepositories.size - 1 &&
incompleteRowCount === 0;

Don't compare against 0:
https://webkit.org/code-style-guidelines/#zero-comparison

>
Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js:1
29
> +	       if (incompleteRowCount === 0)

Ditto.

> Websites/perf.webkit.org/public/v3/models/commit-log.js:59
> -	   if (this == previousCommit)
> +	   if (this === previousCommit)

Why ===? This change should be explained in the change log.

> Websites/perf.webkit.org/public/v3/models/commit-log.js:71
> +	   else if (to.length === 40) // e.g. git hash

What's the point of using ===? There's no difference.

> Websites/perf.webkit.org/public/v3/models/commit-log.js:113
> +	       this._ownedCommits.forEach((ownedCommit) => {
> +		   ownedCommit.setOwnerCommits(this);
> +		  
this._ownedCommitByOwnedRepository.set(ownedCommit.repository(), ownedCommit);
> +	       });

We should add tests to verify these changes are working as intended.

> Websites/perf.webkit.org/public/v3/models/commit-log.js:136
> +	   const ownedCommitRepositories = new Set([].concat(
> +	       ...ownedCommitMapList.map((ownedCommitMap) =>
Array.from(ownedCommitMap.keys()))));

All these constructs to concat arrays with spread just to flatten nested arrays
is really hard to read.
Just write two nested loops.

> Websites/perf.webkit.org/public/v3/models/commit-set.js:80
> +    

Nit: Trailing whitespace.

> Websites/perf.webkit.org/public/v3/models/commit-set.js:256
> +function ensureSetForMap(map, key) {

I don't think we need this helper. It's only used once and it's a simple code.

> Websites/perf.webkit.org/public/v3/models/commit-set.js:267
> +class IntermediateCommitSet {
> +
> +    constructor(commitSet)
> +    {
> +	   this._commitByRepository = new Map;
> +	   this._ownedRepositoriesByOwnerRepository = new Map;

Not only do IntermediateCommitSet store commits instead of revision number, it
also stores owned repositories for each commit?
That's a significant difference worth mentioning in the change log.
Also, IntermediateCommitSet is too vague of a name.
Someone who isn't familiar with this code can't tell the difference between
CustomCommitSet and IntermediateCommitSet.


More information about the webkit-reviews mailing list