# Results
# Participation
In total, 545 participants took part in the experiment. On average, each participant completed 13 exercises, leading to around 250 data points for each snippet.
Just under half of the participants said they had been coding for over 10 years, and around a third had been coding for less than 5 years.
In terms of main programming language, over half the participants said that their main programming language was JavaScript, with the rest spread around a variety of other languages.
# Results by construct
# Boolean Algebra
This experiment was based on the principle that the following expressions are identical.
!a && !b /* expanded */ === !(a || b) /* simplified */
The expanded version on the left (with two separate negations) is exactly equivalent to the simplified version on the right (with a single negation applied to the expression in parenthesis). We wanted to see whether there was any difference in readability between these two ways of expressing combined booleans.
We wrote six exercises with pairs of snippets like the following:
# Expanded
function canDrink(drinkerAge, drinkIsAlcoholic) {
var underAge = drinkerAge < 18;
return !underAge || !drinkIsAlcoholic;
}
var result = canDrink(21, true);
# Simplified
function canDrink(drinkerAge, drinkIsAlcoholic) {
var underAge = drinkerAge < 18;
return !(underAge && drinkIsAlcoholic);
}
var result = canDrink(21, true);
We found a statistically significant difference in the time taken to read the snippets as follows:
Metric | Expanded | Simplified | P value |
---|---|---|---|
Time taken | 28.0 | 30.6 | 0.045 |
It seems that in our tests, the expanded versions of boolean expressions are faster to parse than the equivalent simplified expressions.
# Chaining Methods
This experiment compared the chaining of consecutive methods, with the introduction of meaningful intermediate variables. For example:
# Chaining methods
function sort(input) {
return input
.toLowerCase()
.split('')
.sort()
.join('');
}
var result = sort('bag');
# Intermediate variables
function sort(input) {
var lowerCase = input.toLowerCase();
var lettersArray = lowerCase.split('');
var sorted = lettersArray.sort();
return sorted.join('');
}
var result = sort('bag');
We found a statistically significant difference in both the accuracy and the time taken, but in different directions:
Metric | Chained methods | Intermediate variables | P value |
---|---|---|---|
Accuracy (%) | 89.2 | 93.8 | 0.044 |
Time Taken (s) | 30.5 | 39.3 | 0.001 |
We found that more people were able to accurately predict the outcome of the snippets with intermediate variables. However, the snippets were faster to read with chained methods.
It seems that there is a readability trade-off between the speed of parsing chained methods and the increased context given by the meaningful intermediate variables.
# Extracting Functions
This experiment tested the effect on readability of extracting a series of operations into a named function, as opposed to performing the operations inline. For example:
# Extracted function
function getSum(values) {
var sum = 0;
for (var i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
function getAverage(values) {
return getSum(values) / values.length;
}
result = getAverage([1, 2, 3]);
# Inline operations
function getAverage(values) {
var sum = 0;
for (var i = 0; i < values.length; i++) {
sum += values[i];
}
return sum / values.length;
}
result = getAverage([1, 2, 3]);
We found a statistically significant difference in the time taken to read the code snippets, as follows:
Metric | Function | Inline | P value |
---|---|---|---|
Time taken (s) | 43.0 | 38.4 | 0.048 |
It seems that in our experiment, extracting a named function adds an overhead in the time taken to read the code.
# Order of If Statements
This experiment tested whether there is any effect on the readability of a conditional statement with two branches, in dealing with the branch case first. For example:
# Positive first
function getSalutation(title, firstName, lastName) {
var salutation;
if (title) {
salutation = title + ' ' + lastName;
} else {
salutation = firstName + ' ' + lastName;
}
return salutation;
}
var result = getSalutation('Miss', 'Jane', 'Marple');
# Negative first
function getSalutation(title, firstName, lastName) {
var salutation;
if (!title) {
salutation = firstName + ' ' + lastName;
} else {
salutation = title + ' ' + lastName;
}
return salutation;
}
var result = getSalutation('Miss', 'Jane', 'Marple');
We found a statistically significant difference in the time taken to read the code snippets, as follows:
Metric | Positive first | Negative first | P value |
---|---|---|---|
Time taken (s) | 17.3 | 19.3 | 0.042 |
It seems that in our experiment, conditional statements where the positive condition appears first are faster to read.
# Operator Precedence
This experiment tested whether expressions that are dependent on operator precedence are made more readable by adding parentheses to remove the ambiguity. It should be noted that some code linters, such as prettier, will remove parentheses that are considered unnecessary by default.
For example:
# Parentheses
var fixedCost = 200;
var monthlyCost = 20;
var result = fixedCost + (monthlyCost * 12);
# No parentheses
var fixedCost = 200;
var monthlyCost = 20;
var result = fixedCost + monthlyCost * 12;
We found a statistically significant difference in both the accuracy and the time taken, as follows:
Metric | Parentheses | No Parantheses | P value |
---|---|---|---|
Accuracy (%) | 97.2 | 91.7 | 0.042 |
Time Taken (s) | 17.0 | 19.1 | 0.013 |
It seems clear that readability is improved by adding explicit brackets, rather than relying on the developers' knowledge of operator precedence.
# Pure Functions
This experiment tested whether there was an inherent difference in readability between pure and impure functions. A pure function has no external dependencies or side effects, and always returns the same output for the same input parameters values.
For example, the following snippets have functions expressed in both impure and pure forms.
# Pure
var score = 10;
function doubleScore(initialScore) {
return initialScore * 2;
}
var result = doubleScore(score);
# Impure
var score = 10;
function doubleScore() {
score = score * 2;
}
doubleScore();
var result = score;
We found a statistically significant difference in the time taken to read the code snippets, as follows:
Metric | Pure | Impure | P value |
---|---|---|---|
Time taken (s) | 26.7 | 24.6 | 0.025 |
It seems that in our experiment, writing a pure function adds an overhead in the time taken to read the code.