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

a surveyor for Widget 2-grams #1

Open
pq opened this issue May 2, 2019 · 14 comments
Open

a surveyor for Widget 2-grams #1

pq opened this issue May 2, 2019 · 14 comments
Labels
enhancement New feature or request

Comments

@pq
Copy link
Owner

pq commented May 2, 2019

A jumping off point for iteration is defined in example/widget_surveyor.dart

main(List<String> args) async {
var driver = Driver.forArgs(args);
driver.visitor = WidgetCollector();
await driver.analyze();
}

More details/instructions in the README.

Feedback welcome!

/cc @jayoung-lee @InMatrix

@pq pq added the enhancement New feature or request label May 2, 2019
@pq
Copy link
Owner Author

pq commented May 2, 2019

@jayoung-lee @InMatrix, the current output looks like:

Column->Container : 1
Column->null : 1
Container->Row : 1
Expanded->Column : 1
FlareActor->Container : 1
FlareActor->GestureDetector : 1
FlareActor->Scaffold : 1
GestureDetector->Expanded : 1
HomePage->null : 1
MaterialApp->null : 1
PageView->Scaffold : 1
Row->GestureDetector : 1
Scaffold->Column : 1
Text->Column : 5

where -> signifies "child of" which is pretty arbitrary. Any other ideas most welcome.

@jayoung-lee
Copy link

Great!

I have one suggestion to make analysis easier: Could you replace ":" with "," so that I can easily export this output to a csv file? Actually, it will be awesome if somehow your code can generate such a csv file as an output!

@pq
Copy link
Owner Author

pq commented May 2, 2019

I have one suggestion to make analysis easier: Could you replace ":" with "," so that I can easily export this output to a csv file?

Sure! As of e54bad0, it now emits a list of entries like this:

Column->Container,1

Is that good?

Actually, it will be awesome if somehow your code can generate such a csv file as an output!

That's easy too.

Let's talk about what we want ultimately... One file per project? Or one file for all of them? If it's one file for all of them do we just want total counts?

@jayoung-lee
Copy link

From my perspective, the easiest approach is a single csv file for each analysis (e.g, widget usage, widget 2-gram usage, package usage, etc.) with distinct and consistent patterns in the filename.

I’ll just describe what I anticipate below (based on our conversation so far)!

Let’s say there is a submission titled “flutter_create” and we are interested in widget usage, 2-gram widgets, and package usage. Then I’d expect three files,

“flutter_create_2gram.csv”
“flutter_create_widget.csv”
“flutter_create_package.csv”

Then the csv file that contains 2-gram analysis results may be titled flutter_create_2gram.csv with these:

Column->Container, 1
Column->null, 1
Container->Row, 1
Expanded->Column, 1
FlareActor->Container, 1
FlareActor->GestureDetector, 1
FlareActor->Scaffold, 1
GestureDetector->Expanded, 1
HomePage->null, 1
MaterialApp->null, 1
PageView->Scaffold, 1
Row->GestureDetector, 1
Scaffold->Column, 1
Text->Column, 5

Similarly, for the general widget usage analysis (i.e., counting the number of widget appearance in the code), I’d expect something like flutter_create_widget.csv that has:

Column, 7
GestureDetector, 1
Expanded, 10
Container, 3
FlareActor, 4
Text, 10
…

And for packages, flutter_create_package.csv and something like above.

In addition to these files, If we have some interesting submission-level stats, we can also have a single summary file for all of the submissions (summary.csv), each row being a submissions and each column being a summary stat, such as:

submission_name, unique_widgets_count, unique_2grams_count // this is a header and may be expanded with any summary measures we find interesting
flutter_create, 22, 34
project_a, 30, 35
project_b, 25, 28
…

Taken all together, the widget_surveyor may generate a set of files:

“summary.csv”
“flutter_create_2gram.csv”
“flutter_create_widget.csv”
“flutter_create_package.csv”
“project_a_2gram.csv”
“project_a_widget.csv”
“project_a_package.csv”
“project_b_2gram.csv”
“project_b_widget.csv”
“project_b_package.csv”
…

Does this make sense to you? Am I missing anything? I’m open to any suggestions! :)

@pq
Copy link
Owner Author

pq commented May 9, 2019

Sounds good!

So far I've got support for 2 grams.

Running dart example/widget_surveyor.dart test/data yields two files:

[~/src/repos/surveyor] (master) $ dart example/widget_surveyor.dart test/data
Recursing into "test/data"...
Checking dependencies...
Analyzing...
Analyzing "basic_app"...
Writing 2-Grams to "basic_app_2gram.csv"...
Analyzing "animated_container"...
Writing 2-Grams to "animated_container_2gram.csv"...
Finished.
No issues found!

[~/src/repos/surveyor] (master) $ cat basic_app_2gram.csv 
AppBar->Scaffold,1
Center->AppBar,1
Column->Center,1
FloatingActionButton->Column,1
Icon->FloatingActionButton,1
MaterialApp->null,1
MyApp->null,1
MyHomePage->null,1
Scaffold->null,1
Text->AppBar,1
Text->Column,3

[~/src/repos/surveyor] (master) $ cat animated_container_2gram.csv 
AnimatedContainer->Center,1
AnimatedContainerApp->FloatingActionButton,1
AppBar->Scaffold,2
Center->AppBar,2
Column->Center,1
FloatingActionButton->Center,1
FloatingActionButton->Column,1
Icon->FloatingActionButton,2
MaterialApp->FloatingActionButton,1
MaterialApp->null,1
MyApp->null,1
MyHomePage->null,1
Scaffold->MaterialApp,1
Scaffold->null,1
Text->AppBar,2
Text->Column,3

I'll take a look at widget counts and summaries in a bit.

In the meantime, @jayoung-lee: does this look about right?

@jayoung-lee
Copy link

Looks perfect!

@pq
Copy link
Owner Author

pq commented May 10, 2019

Widget counts are being collected now:

[~/src/repos/surveyor] (master) $ cat animated_container_widget.csv 
MyApp, 1
MaterialApp, 2
MyHomePage, 1
Scaffold, 2
AppBar, 2
Text, 5
Center, 2
Column, 1
FloatingActionButton, 2
Icon, 2
AnimatedContainerApp, 1
AnimatedContainer, 1

[~/src/repos/surveyor] (master) $ cat basic_app_widget.csv 
MyApp, 1
MaterialApp, 1
MyHomePage, 1
Scaffold, 1
AppBar, 1
Text, 4
Center, 1
Column, 1
FloatingActionButton, 1
Icon, 1
[~/src/repos

@jayoung-lee: as a next step I think we should do some validation. Perhaps we could select a project or two, do a manual count and verify that the results are as expected?

@jayoung-lee
Copy link

Sounds like a good idea! If you could pick a couple of examples (ones that you've already run the surveyor on?), I will take a look at them.

@pq
Copy link
Owner Author

pq commented May 10, 2019

As a quick sanity check, you could look at the two projects checked into test/data.

Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Pushed',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
Text(
'times',
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}

and

Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('AnimatedContainer Demo'),
),
body: Center(
child: AnimatedContainer(
// Use the properties stored in the State class.
width: _width,
height: _height,
decoration: BoxDecoration(
color: _color,
borderRadius: _borderRadius,
),
// Define how long the animation should take.
duration: Duration(seconds: 1),
// Provide an optional curve to make the animation feel smoother.
curve: Curves.fastOutSlowIn,
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.play_arrow),
// When the user taps the button
onPressed: () {
// Use setState to rebuild the widget with new values.
setState(() {
// Create a random number generator.
final random = Random();
// Generate a random width and height.
_width = random.nextInt(300).toDouble();
_height = random.nextInt(300).toDouble();
// Generate a random color.
_color = Color.fromRGBO(
random.nextInt(256),
random.nextInt(256),
random.nextInt(256),
1,
);
// Generate a random border radius.
_borderRadius =
BorderRadius.circular(random.nextInt(100).toDouble());
});
},
),
),
);
}

Their 2-grams and counts are inlined in the comments above (#1 (comment) and #1 (comment) respectively.)

@InMatrix
Copy link

Wow, nice progress!

Some minor feedback on the notation:

where -> signifies "child of" which is pretty arbitrary. Any other ideas most welcome.

Would it be more intuitive to have -> signify "parent of", since the parent is on the left (and upper) side of the child in the code? I was initially puzzled by Text->AppBar, assuming Text was the parent.

@pq
Copy link
Owner Author

pq commented May 11, 2019

Would it be more intuitive to have -> signify "parent of"

Totally up to you! I think my point of reference was inheritance diagrams where -> means "subtype of" but that's not really the same thing either. 😬

Another thought is to be less suggestive and just use a delimiter like : for the pairing.

Whatever makes the most sense to you all works for me and it's an easy change!

@jayoung-lee
Copy link

I took a look at the basic_app first. This is what the Flutter Outline gives me:

image

So I guess the FloatingActionButton Is under Scaffold instead of Column? The surveyor output says FloatingActionButton->Column,1. Similarly, Center is under Scaffold instead of AppBar?

And for the widget counts, why was MaterialApp counted twice? Is it because MyApp extends MaterialApp and returns a new MaterialApp again? It makes other widgets, for example FloatingActionButton, counted twice as well. I thought what we want to count is the number of the widget's appearance in the code itself, but I might be wrong.. WDYT @pq and @InMatrix ?

And I'd like +1 to @InMatrix 's suggestion, just because it is easier for humans to read (or me!). I find it much easier to read things top-down and left-to-right :) For example,

null -> Scaffold, 1
Scaffold -> AppBar, 1
AppBar -> Text, 1
Scaffold -> Center, 1
Center -> Column, 1
Column -> Text, 3
Scaffold -> FloatingActionButton, 1
FloatingActionButton -> Icon, 1

@pq
Copy link
Owner Author

pq commented May 15, 2019

Ok, so that was obviously not right! Thanks for taking a look (though I should probably have noticed 😬).

Here's where we are after some fixes:

[~/src/repos/surveyor] (master) $ cat basic_app_2gram.csv 
AppBar -> Text, 1
Center -> Column, 1
Column -> Text, 3
FloatingActionButton -> Icon, 1
MaterialApp -> MyHomePage, 1
Scaffold -> AppBar, 1
Scaffold -> Center, 1
Scaffold -> FloatingActionButton, 1
null -> MaterialApp, 1
null -> MyApp, 1
null -> Scaffold, 1

At a quick inspection that looks closer to the outline:

image

But please do double-check!

@jayoung-lee
Copy link

No worries! The new output looks correct to me too :D

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

No branches or pull requests

3 participants