-
Notifications
You must be signed in to change notification settings - Fork 8
Add a central module to handle the metric data #34
Conversation
- to avoid case-sensitivity issues, change paths to be all lower-case - also use .jsx for components for automatic syntax highlighting in editors
React likes things to be named index.js apparently, let’s go with it.
- to avoid case-sensitivity issues, change paths to be all lower-case - also use .jsx for components for automatic syntax highlighting in editors
React likes things to be named index.js apparently, let’s go with it.
# Conflicts: # src/app.jsx
Also save some repetition from re-using variables.
John, does this approach make sense to you? |
Or to you Davor? |
prevState.activeVersion !== this.state.activeVersion) { | ||
this.dataStore.loadDataFor(this.state.activeMetric, this.state.activeChannel, this.state.activeVersion) | ||
.then(() => this.setState({activeData: this.dataStore.active.data})); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Memoization might make this section a little cleaner:
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting, thanks.
I may have to digest that a bit and look into it in a follow-up.
I can't say I'm an expert at state management in React, but this seems fine to me. It's pretty straightforward. @spasovski any other feedback? |
src/components/summaryview.jsx
Outdated
|
||
let metric = this.props.dataStore.active.metric; | ||
let channel = this.props.dataStore.active.channel; | ||
let version = this.props.activeVersion; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: these look like they cold be const
src/metricdata.js
Outdated
let bucketHits = 0; | ||
let linearTerm = (buckets[buckets.length - 1] - buckets[buckets.length -2]) / 2; | ||
let exponentialFactor = Math.sqrt(buckets[buckets.length - 1] / buckets[buckets.length - 2]); | ||
let useLinearBuckets = this.kind === "linear" || this.kind === "flag" || this.kind === "boolean" || this.kind === "enumerated"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could also do let useLinearBuckets = ['linear', 'flag', 'boolean', 'enumerated'].includes(this.kind);
src/metricdata.js
Outdated
} | ||
|
||
loadDataFor(metric, channel, version) { | ||
return fetch("https://mozilla.github.io/mdv2/data/" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the fetch url could be "https://mozilla.github.io/mdv2/data/${metric}_${channel}_${version}.json
" with string interpolation
]; | ||
} | ||
|
||
get versionOptions() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't seen this get
syntax before. Very java-ey
Am I wrong in thinking Redux wasn't used here? Not trying to vote for or against...that's a slightly more involved conversation. John's momoization link is good reading and some of the components could be pure. I don't have greater insight into this project but the logic itself seems fine and I like the trimming of the previously massive component into something that gets its state externally. |
Thanks John & Davor, looking into it. |
This is correct. I heard some light feedback that Redux would solve the problem at hand (centralizing data handling) but is probably more complex than required. Thus i'm testing this out as an alternative, more straight-forward solution. |
- use more `const` - more readable template string - more readable metric kind comparison
nfifthPercentile: "", | ||
median: "", | ||
mean: "", | ||
lastMedian: 315, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's oddly specific
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is copied code, let's get to that later.
metric: this._active.metric, | ||
channel: this._active.channel, | ||
version: this._active.version, | ||
data: this._active.data, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While we're having fun with ES6, this can be rewritten as return {...this._active};
} | ||
|
||
updateCachedData() { | ||
this.cached.mean = this.getMean().toFixed(2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this.mean
returns full-precision numbers, then I think this.cached.mean
should be full-precision as well.
src/metricdata.js
Outdated
} | ||
|
||
async loadDataFor(metric, channel, version) { | ||
const response = await fetch(`https://mozilla.github.io/mdv2/data/${metric}_${channel}_${version}.json`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A relative URL could make testing easier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get to that when the need comes up.
src/metricdata.js
Outdated
this._active.metric = metric; | ||
this._active.channel = channel; | ||
this._active.version = version; | ||
this._active.data = data; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More ES6 wizardry: this._active = {...this._active, metric, channel, version, data};
return this.getChange(); | ||
} | ||
|
||
updateCachedData() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We aren't caching data, though, we're caching aggregates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still cached data though?
This caching we may want to revisit soon, currently this is mostly copied over and adopted to make work.
} | ||
|
||
getMean() { | ||
let currentData = this._active.data; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a proponent of making const
whatever we can make const
. So here that'd be currentData, buckets, values, linearTerm, exponentialFactor, useLinearBuckets, centralX
or so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh, wait this is copied from erin's impl elsewhere. Nevermind, then.
- buckets[buckets.length -2]; | ||
}*/ | ||
|
||
return buckets[buckets.length - 1] * buckets[buckets.length - 1] / buckets[buckets.length - 2]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's two spaces after return
here
|
||
getChange() { | ||
let rawChange = this.getPercentile(50) - this.cached.lastMedian; | ||
let pctChange = (rawChange / this.cached.lastMedian) * 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.cached.lastMedian
is never written to? Oh, I guess that's a TODO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the lastMedian
approach needs revisiting anyway (currently it doesn't show it from the preceding version, but from the last-loaded version).
@chutten Please take a look over it. Let's aim for identifying improvements as follow-ups where possible. One follow-up thing (existing issue) i've identified is that switching to scalars_devtools_onboarding_is_devtools_user results (in the summary view) in the median value of infinity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I leave you to decide which comments are appropriate to address now and which as follow-ups (and which to ignore and evaluate later as part of a generic cleanup sweep).
getLastBucketUpper
has commented out code that requires information about what the type of measurement is. We don't have that information, but scalars_devtools_onboarding_is_devtools_user
is a metric that requires the special handling. I'm not worried about that at this state as it will require broader changes to make correct.
In general I'm happy with the move and the reorganization, so in my opinion it is merge-able.
Ok, moving forward with the merge. |
Having more conversations on the usage of Redux, it does the job of centralizing the data state but might be more complex than what we need.
As an alternative to the Redux migration #26 i'm testing out moving the metric data handling into a separate module,
MetricData
/ metricdata.js.This centrally handles:
From there we can:
MetricData
inApp