-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.htm
318 lines (288 loc) · 28.5 KB
/
index.htm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta property="og:title" content="Evolution of the Firefox Codebase" />
<meta property="og:description" content="This work presents a set of metrics for all releases of Firefox that are indicative of quality and allows one to inspect them through one of several views. By looking at changes in these metrics, one can see the evolution of the Firefox codebase over time. This work is also be useful as a retrospective, investigative tool to help infer when, say, architectural issues may be the cause for unfavorable user sentiment following a release." />
<meta property="og:image" content="http://almossawi.com/fx-logo.png" />
<meta property="og:type" content="website" />
<meta property="og:url" content="http://almossawi.com/firefox" />
<meta property="og:site_name" content="Evolution of the Firefox Codebase" />
<title>Evolution of the Firefox Codebase</title>
<link href='https://fonts.googleapis.com/css?family=Cardo' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Signika:400,300' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,300,600" rel="stylesheet" type="text/css" />
<link href='https://fonts.googleapis.com/css?family=PT+Sans:400,700' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Old+Standard+TT:400,400italic,700' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js" type="text/javascript"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<!--<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery-ui.min.js"></script>
<script type="text/javascript" src="js/d3.v3.min.js"></script>-->
<script src="js/underscore.min.js" type="text/javascript"></script>
<script type="text/javascript" src="data/modules_data.js"></script>
<script type="text/javascript" src="js/global.js"></script>
<script type="text/javascript" src="js/jquery.uniform.min.js" charset="utf-8"></script>
<link rel="stylesheet" href="css/styles.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="css/uniform.default.css" type="text/css" charset="utf-8" />
</head>
<body>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-35624223-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<div id="main_options">
<a href="#" id="switch_to_matrix">
<div style="border-right:1px solid #3b3b3b">MATRIX
<div class="selected_view"></div>
</div>
</a>
<a href="#" id="switch_to_chart">
<div style="border-right:1px solid #3b3b3b">CHART
<div class="selected_view"></div>
</div>
</a>
<a href="#" id="switch_to_network">
<div>NETWORK
<div class="selected_view"></div>
</div>
</a>
</div>
<div id="page">
<div id="version_select">
<a href="#">
<img src="images/lhs_left.png" id="lhs_left" class="version_arrow" />
</a>
<a href="#">
<img src="images/lhs_right.png" id="lhs_right" class="version_arrow" />
</a>
<div id="versions_lhs_and_rhs">
<div id="lhs_version_header"></div>
<img src="images/firefox_tiny.png" />
<div id="rhs_version_header"></div>
</div>
<a href="#">
<img src="images/rhs_left.png" id="rhs_left" class="version_arrow" />
</a>
<a href="#">
<img src="images/rhs_right.png" id="rhs_right" class="version_arrow" />
</a>
</div>
<div id="metric">
<div id="chart_view" class="view">
<div id="loc_code" class="topmetric"></div>
<div id="mccabe_per_kloc_code" class="topmetric"></div>
<div id="dependencies_density" class="topmetric"></div>
<div id="prop_cost" class="topmetric"></div>
<div id="percent_in_core_at_discontinuity" class="topmetric"></div>
<div id="files_with_dependencies" class="topmetric"></div>
<div id="percentage_change_switch">
<!--<a href="#">
SHOW PERCENTAGE CHANGE INSTEAD?
</a>-->
</div>
</div>
<div id="matrix_view" class="view">
<!--<div id="labels">
<div id="lhs">Firefox 16</div>
<div id="rhs">Firefox 17</div>
</div>-->
<div id="canvases">
<div id="loading_matrices">Generating matrices...</div>
<img src="images/matrix_blank.png" id="canvas1" />
<img src="images/matrix_blank.png" id="canvas2" />
<!--<canvas id="canvas1" width="500" height="500"></canvas>
<canvas id="canvas2" width="500" height="500"></canvas>-->
<div style="clear:both"></div>
<div id="lhs_core_periph" class="core_periph">FILES: <span id="lhs_files">...</span> DENSITY: <span id="lhs_density">...</span></div>
<div id="rhs_core_periph" class="core_periph">FILES: <span id="rhs_files">...</span> DENSITY: <span id="rhs_density">...</span></div>
<a href="#" id="what_mean_matrix">
<img src="images/what_mean.png" />
</a>
<div id="matrix_modal">
<a href="#" id="close_modal">
<img src="images/x.png" />
</a>
<h1>What does this mean?</h1>
<p>These adjacency matrices, sometimes called Design Structure Matrices (DSMs), show direct dependencies between files in a codebase. A dot represents one or more dependencies and is read</p>
<p style="text-align:center"><span style="font-style:italic;font-family:Palatino, Georgia, 'PT Serif', Times">file A depends on file B</span>
</p>
<p>where A is a file along the left edge and B is a file along the top edge. A module's dependencies are colored distinctly. A square-shaped cluster indicates the density of dependencies within a module.</p>
<p>All the dots to the right and left of a cluster are files that the module depends on. All files above and below it are files that depend on it. In many paradigms, modularity (low coupling, high cohesion) is a desirable quality attribute. Hence, an ideal
system has modules that have more intra-module dependencies and fewer inter-module dependencies.</p>
<p>A matrix can show different types of files, which have varying impacts on quality. Although we calculate the values for these four types of files using the visibility matrix, it is still useful to look for them in a first-order matrix. <span style="font-weight:600">Shared files</span>,
also known as utility files, are ones that a lot of other files depend on; a shared file that every other file in a codebase depends on would appear as a solid vertical line in an adjacency matrix. Shared files appear to be a positive predictor of quality.</p>
<p><span style="font-weight:600">Control files</span>, conversely, depend on a high number of files. Such files appear to be a negative predictor of quality and are hence undesirable in high numbers. They may appear as horizontal lines in an adjacency matrix.</p>
<p>Two other types of files are <span style="font-weight:600">core files</span>, which depend on a lot of files and have a lot of files depend on them, and <span style="font-weight:600">periphery files</span>, which don't depend on a lot of files and don't have a lot of files depend on them. These
may be a bit more difficult to spot in a matrix. The collective size of clusters can give a partial sense of the number of core files in a codebase. Core files seem to be a negative predictor of quality whereas periphery files seem to be a positive predictor
of quality.</p>
</div>
</div>
<div id="modules_legend"></div>
<div id="matrix_options">
<input type="radio" name="matrix_showallcalls" value="1" checked>
<label>color all dependencies</label>
<input type="radio" name="matrix_showallcalls" value="0">
<label>color only inter-module dependencies</label>
</div>
<div id="matrix_description">
<!--<p>These matrices show direct dependencies between files. A dot represents one or more dependencies and is read <span style="font-style:italic;font-family:Palatino, Georgia, 'PT Serif', Times">file A depends on file B</span>, where A is a file along the left edge and B is a file along the top edge. A module's dependencies are colored distinctly. A square-shaped cluster indicates the density of dependencies within a module. All the dots to the right and left of a cluster are files that the module depends on. All files above and below it are files that depend on it. In many paradigms, modularity, which is to say, low coupling and high cohesion, is a desirable quality attribute. Hence, an ideal system has modules that have more intra-module dependencies and fewer inter-module dependencies.</p>-->
</div>
</div>
<div id="network_view" class="view">
<div style="margin-left:auto;margin-right:auto;text-align:center;margin-top:20px">
<!--<img src="http://25.media.tumblr.com/tumblr_lo576hVkgi1qgwon1o1_500.jpg" />-->
<img src="images/soon.png" />
</div>
</div>
</div>
<div style="clear:both"></div>
<div id="container">
<div style="margin-top:40px;text-align:left">
<p><span style="font-weight:600;font-style:italic">Evolution of the Firefox Codebase</span> presents a set of metrics for all releases of Firefox that are indicative of quality and allows one to inspect them through one of several views. By looking at changes in these metrics, one can see the evolution of the Firefox codebase over time. This work is also be useful as a retrospective, investigative tool to help infer when, say, architectural issues may be the cause for unfavorable user sentiment following a release. Metrics such as lines-of-code (LOC) and cyclomatic complexity are widely used in industry, whereas others like propagation cost are based on some of the more recent research to come out of academia.</p>
<p>Only modules that have a reasonable level of complexity, i.e. several hundred files, are shown. Select an option from the top to change the view. In the <i>Chart</i> view, to see how much a metric has changed between two releases on the same axis, use <span class="key">z</span> and the <span class="key">left</span> and <span class="key">right</span> arrow keys to cycle through versions on the left-hand side and <span class="key">x</span> and the arrow keys to cycle through versions on the right-hand side. Descriptions of what each metric captures and how it is calculated are shown below, as are some additional measures of quality, such as speed and resident memory usage, both of which have improved in Firefox.</p>
<p>For more, please read my post <a href="prose" style="border-bottom:1px dotted #cccccc">How maintainable is the Firefox codebase?</a></p>
<br />
</div>
<div id="below_fold_options">
<!--<div id="below_fold_actual_values_switch" class="below_fold_switch selected">VALUES</div>
<div id="below_fold_percentage_change_switch" class="below_fold_switch">PERC. CHANGE</div>-->
</div>
<div style="clear:both"></div>
<div id="chart_container_container">
<div class="chart_description">
<h1>LOC</h1>
<p>LOC measures the number executable lines of code in each release, ignoring comments and blank lines, and is widely used as a baseline measure of quality. A system with more LOC is typically more difficult to maintain. LOC and defect density have an inverse relationship<sup>1</sup> due to architecture not changing at the same rate as LOC and architectural elements such as interfaces having a higher propensity for defects than individual components.</p>
<p>The set of analyzed files includes all files that meet our file-type filter<sup>2</sup> and excludes unit tests.</p>
<p class='footy'><sup>1</sup> Stephen Kan, S., Metrics and Models in Software Quality (2002).</p>
<p class='footy'><sup>2</sup> .c, .C, .cc, .cpp, .css, .cxx, .h, .H, .hh, .hpp, .htm, .html, .hxx, .inl, .java, .js, .jsm, .py, .s, .xml</p>
</div>
<div class="chart_container" id="allversions_loc_code_no_unit_tests"> <span class="container_title">LOC</span>
<div></div>
</div>
<div class="chart_description">
<h1>Cyclomatic complexity</h1>
<p>Cyclomatic complexity, developed by Thomas McCabe in 1976, measures the number of linearly independent paths within a software system and can be applied either to the entire system or to a particular class or function. By viewing a block of code as a control graph, the nodes constitute indivisible lines of code that execute in sequence and the directed edges connect two nodes if one can occur after the other. So, for example, branching constructs like if-else statements would result in a node being connected to two output nodes, one for each branch.</p>
<p>Cyclomatic complexity is defined as <i>v(G) = e – n + 2p</i> where v(G) is the cyclomatic number of a graph G, e is the number of edges, n is the number of nodes and p is the number of connected components, or exit nodes, in the graph. A block of code with a single set of if-else statements would be calculated as follows: e = 6, n = 6 and p = 1, therefore, v(G) = 6 – 6 + 2 * 1 = 2. The additive nature of the metric means that the complexity of several graphs is equal to the sum of each graph. In our measure of cyclomatic complexity, we control for size and hence, the value for each release is per 1,000 LOC.</p>
</div>
<div class="chart_container" id="allversions_mccabe_per_kloc_no_unit_tests"> <span class="container_title">Cyclomatic complexity</span>
<div></div>
</div>
<div style="clear:both"></div>
<div class="chart_description">
<h1>First-order density</h1>
<p>First-order density measures the number of direct dependencies between files. It is calculated by first building an adjacency matrix, sometimes called a Design Structure Matrix (DSM), using the set of source-code files sorted by their hierarchical directory structure. Wherever a file in a particular row depends on a file in a particular column, we mark the element with a '1'. Because we're only capturing direct dependencies, this matrix is referred to as a first-order dependency matrix. The density of said matrix is the first-order density. For releases, we show it per 10,000 file pairs whereas for modules, where matrices are generally not as sparse, we show the density as a percentage.</p>
<p>In such a matrix, a square-shaped cluster indicates many dependencies between files within a module. All the dots to the right and left of a cluster are files that the module depends on. All files above and below it are files that depend on it. In many paradigms, modularity (low coupling, high cohesion) is a desirable quality attribute. Hence, an ideal system has modules that have more intra-module dependencies and fewer inter-module dependencies.</p>
</div>
<div class="chart_container" id="allversions_dependencies_density_per_ten_thousand_file_pairs_no_unit_tests">
<span class="container_title">First-order density</span>
<div></div>
</div>
<div style="clear:both"></div>
<div class="chart_description">
<h1>Propagation cost</h1>
<p>Propagation cost measures direct as well as indirect dependencies between files in a codebase. In practical terms, it gives a sense of the proportion of files that may be impacted, on average, when a change is made to a randomly chosen file<sup>3,4</sup>.
<p>The process of transforming a first-order dependency matrix that captures only direct dependencies between files to a visibility matrix, also known as a reachability matrix, that captures indirect dependencies as well is achieved through matrix multiplication by raising the first-order dependency matrix to multiple successive powers until we achieve its transitive closure. Thus, a matrix raised to the power of two would show the indirect dependencies between elements that have a path length of two, i.e. calls from A to C, if A calls B and B calls C. Thereafter, by summing these matrices together one gets the visibility matrix. For this ripple effect to be of use in analysis, the density of the visibility matrix is captured within the metric that we call propagation cost.</p>
<p class="footy"><sup>3</sup> Alan MacCormack, John Rusnak and Carliss Baldwin, <i>Exploring the Structure of Complex Software Designs: An Empirical Study of Open Source and Proprietary Code</i> (2006).</p>
<p class="footy"><sup>4</sup> Steven D. Eppinger and Tyson R. Browning, Design Structure Matrix Methods and Applications (2012).</p>
</div>
<div class="chart_container" id="allversions_prop_cost_no_unit_tests">
<span class="container_title">Propagation cost</span>
<div></div>
</div>
<div style="clear:both"></div>
<div class="chart_description">
<h1>Core size</h1>
<p>Core files are files that are highly interconnected via a chain of cyclic dependencies and have been shown in various studies to have a higher propensity for defects<sup>5</sup>. They are one of four types of files that one sees when plotting files along the axes of fan-in and fan-out, the intuition for this breakout being that different directions and magnitudes of dependencies have varying impacts on software quality. This intuition has been validated by several studies and a smaller core has been shown to result in fewer defects. Core size is the percentage of files with one or more dependencies that have a high fan-in and a high fan-out.</p>
<p>Other types of files are peripheral files, which don’t depend on a lot of files and don't have a lot of files depend on them (low fan-in, low fan-out); shared files, which don’t depend on a lot of files, but have a lot of files depend on them (high fan-in, low fan-out) and control files, which depend on a lot of files, but don’t have a lot of files depend on them (low fan-in, high fan-out).</p>
<p class="footy"><sup>5</sup> Alan MacCormack and Dan Sturtevant, System Design and the Cost of Complexity: Putting a Value on Modularity (2011).</p>
</div>
<div class="chart_container" id="allversions_percent_in_core_at_discontinuity_no_unit_tests">
<span class="container_title">Core size</span>
<div></div>
</div>
<div style="clear:both"></div>
<div class="chart_description">
<h1>Defect density</h1>
<p>Defect density measures the number of confirmed bugs in each release per 100,000 LOC. A set of http queries are run against Mozilla's bug tracking system, Bugzilla, to get the counts per release. Since the <i>version</i> field in Bugzilla is an optional field, the defect counts currently don't include confirmed bugs that have not been assigned to particular releases. We have a relatively robust method for including unassigned defects that we may end up using in the future. We start from version 5.0 since that is when the rapid release cycle began.</p>
</div>
<div class="chart_container" id="allversions_defects_per_hundred_thousand_loc_code">
<span class="container_title">Defect density</span>
<div></div>
</div>
<div style="clear:both"></div>
<div class="chart_description">
<h1>Resident memory</h1>
<p>This metric captures the amount of resident memory used after Mozilla's TP5 test is left running for 30 seconds. Resident memory is the physical amount of memory used by the Firefox process. The TP5 test, run five times in sequence, loads a set of 100 popular webpages into the browser, with a ten-second delay between each page load.</p>
<p>We run our memory usage tests on builds from mozilla-central. The result for each release is based on the latest test that was done on the code in mozilla-central before it was branched off to its release-specific branch. There is a gap of a number of weeks between that codebase and the codebase of the final release, hence it is important to keep this caveat in mind when interpreting the data.</p>
<p>This data is provided by our colleagues at areweslimyet.com. See their <a href="https://areweslimyet.com/faq.htm">FAQ</a> for more info.</p>
<p><i>note: v20 saw two regressions that were fixed prior to the release. See <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=820602">this</a> and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=833518">this</a>. Since data points here are taken from mozilla-central several weeks before a release, the data point for v20 has been taken out.</i></p>
</div>
<div class="chart_container" id="allversions_mem">
<span class="container_title">Resident memory</span>
<div></div>
</div>
<div class="chart_description">
<h1>Speed</h1>
<p>Up until version 19, this metric shows the V8 score of each release. From version 20 onwards, it shows the Octane score, which succeeded the V8 benchmark suite. We run our speed tests on builds from mozilla-central. As before, the score for each release is based on the latest test that was done on the code in mozilla-central before it was branched off to its release-specific branch. There is a gap of a number of weeks between that codebase and the codebase of the final release. Also worth noting is that the IonMonkey JavasScript engine was introduced in version 18, which noticeably improved Firefox's score and accounts for the increase in speed performance from then on. A higher score indicates better performance.</p>
<p>The data is provided by our colleagues at arewefastyet.com.</p>
<!--<p class='footy'><sup>5</sup> David Anderson, IonMonkey in Firefox 18, https://blog.mozilla.org/javascript/2012/09/12/ionmonkey-in-firefox-18</p>-->
</div>
<div class="chart_container" id="allversions_speed">
<span class="container_title">Speed</span>
<div></div>
</div>
<div style="clear:both"></div>
<div id="wide_pane">
<div id="twitter_block">
<a href="https://twitter.com/share" data-size="large" class="twitter-share-button" data-url="almossawi.com/firefox" data-text="Evolution of the Firefox codebase, http://almossawi.com/firefox">Tweet</a>
<script>
! function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");
</script>
</div>
<div id="fb_block" class="fb-like" data-href="http://almossawi.com/firefox" data-send="false" data-layout="box_count" data-width="150" data-show-faces="false" data-font="arial"></div>
<div id="credits_block">
<a href="http://almossawi.com" style="border-bottom:0">ALI ALMOSSAWI</a> · ali@mozilla.com · This is still a work-in-progress; please get in touch for all thoughts and comments ·
<!--<a href="https://twitter.com/alialmossawi">Follow me on Twitter</a> ·-->May 2013
<br />Background image courtesy of <a href="https://twitter.com/tyronflanagan">Ty Flanagan</a>. This project is being released under a Creative Commons license (<a href="http://creativecommons.org/licenses/by-nc/3.0/">CC BY-NC</a>).
</div>
<div style="float:right;padding-top:17px">
<iframe src="http://ghbtns.com/github-btn.html?user=almossawi&repo=Firefox-Codebase-Evolution&type=watch&size=large" allowtransparency="true" frameborder="0" scrolling="0" width="80" height="30" style="float:right"></iframe>
<!--<iframe src="http://ghbtns.com/github-btn.html?user=almossawi&type=follow&size=large" allowtransparency="true" frameborder="0" scrolling="0" width="200" height="30" style="float:right"></iframe>-->
</div>
</div>
</div>
<!-- end #container -->
</div>
</div>
<script>
var images = [
'images/lhs_left.png',
'images/lhs_right.png',
'images/rhs_left.png',
'images/rhs_right.png',
'images/bg-sand.png',
'images/matrix_blank.png'
];
$(images).each(function () {
var image = $('<img />').attr('src', this);
});
</script>
</body>
</html>