CO559: Software Engineering
Code quality






Tomas Petricek

email: t.petricek@kent.ac.uk
twitter: @tomaspetricek
office: S129A

Code quality

Software Maintenance

You spend more time reading and modifying code than writing it.

Investing into readability when writing pays off

eXtreme Programming (2000s)

Keeping code simple

  • Write self-documenting code
  • Reduce need for comments
  • You Ain't Gonna Need It (YAGNI)

Shared understanding in a team

  • Common coding standards
  • Pair programming
  • Use of code reviews

Code for readability

Always code as if the person maintaining your code will be a violent psychopath who knows where you live.

The person maintaining it will likely be future you.

What is good quality code?

Hacker culture

  • Quality is learned by experience
  • Apprenticeships if coding was craft
  • Good examples, but no written rules

Coding standards

  • Explicit rules that one can follow
  • There are often exceptions
  • Good starting point, but not ultimate answer

Do programming languages matter?

[It] appear[s] that strong typing is modestly better than weak typing, and among functional languages, static typing is also somewhat better than dynamic typing.

Do programming languages matter?

Attempt to reproduce the study mostly failed

"I believe they do in my heart of hearts, but it's kind of an impossible experiment to run."

Code quality

Aspects of code quality

  • Variable and function names
  • Structure of code logic
  • Organization of functionality

Processes for keeping quality

  • Improving quality through refactoring
  • Ensuring code quality using tools
  • Ensuring code quality using social processes

Naming

Good naming is easy today!

Computers supports
lower case letters!

Long names fit in
computer memory

Auto-complete helps
you avoid typos

Naming of variables (1/3)

What is the following function doing?

1: 
2: 
3: 
function conv(x) {
  return x * 9 / 5 + 32;
}

Converting temperature from Celsius to Fahrenheit!

1: 
2: 
3: 
function celsiusToFahrenheit(temperature) {
  return temperature * 9 / 5 + 32;
}

Naming of variables (2/3)

Was that descriptive enough?

1: 
2: 
3: 
4: 
function convertTemperatureFromCelsiusToFahrenheit
    (temperatureInCelsius) {
  return temperatureInCelsius * 9 / 5 + 32;
}

Can we improve this by using abbreviations?

1: 
2: 
3: 
function convTempFromCelsToFahr(tempInCels) {
  return tempInCels * 9 / 5 + 32;
}

Naming of variables (3/3)

Are all variable names in this example descriptive?

1: 
2: 
3: 
var result = 0;
for(var i = 0; i < data.length; i++) result += data[i];
return result;

This is too much. Sensible exceptions allowed!

1: 
2: 
3: 
4: 
var resultNumber = 0;
for(var dataIndex = 0; dataIndex < data.length; dataIndex++)
  resultNumber += data[dataIndex];
return resultNumber;

Naming of variables

Descriptive names of reasonable length

Name should add semantic information

No need to say it's number, string, etc.

Longer names are good, but don't overdo it!

Follow common conventions where applicable

The more local, the less it matters

Naming of variables, functions and classes

Combining words in names

  • PascalCase
  • camelCase
  • snake_case

Using spaces in a name

  • Would makes code nightmare to parse
  • Some language allow escaping e.g. ``funny name!``

Naming of classes and methods in Java

Is the following naming consistent or not?

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
public class Program {
   public Program(Boolean adminMode) {
     // Some actual logic here
   }
   public static void main(String []args) {
      Program prog = new Program(false);
   }
}

Pascal case Program, camelCase adminMode, main

Naming classes and other issues

Coding standards and exceptions

Java standards use PascalCase for class names

camelCase is used for variables and method names

You should generally follow coding standards

Exceptions such as numerical code: P or alpha

Structure and whitespace

GOTO considered harmful

Can you tell what this does?

1: 
2: 
3: 
4: 
10: I = 1
20: PRINT "HI"
30: I = I + 1
40: IF I <= 10 THEN GOTO 20

And what about this?

1: 
2: 
3: 
FOR I = 1 TO 10 DO
  PRINT "HI"
NEXT

Keeping program logic simple

Is there an easier way to write this?

1: 
2: 
if (isAdministrator(user) || isOwner(user)) return true;
else return false;

You do not need conditional statement at all!

1: 
return isAdministrator(user) || isOwner(user);

Keeping program logic ... logical (1/2)

When does the following return a product page?

1: 
2: 
3: 
4: 
5: 
6: 
7: 
if (isAvailable(product)) {
  if (isHidden(product))
    return null;
  return getProductPage(product);
} else {
  return null;
}

When product is available and not hidden!

Which branch is the "happy path" branch?

Keeping program logic ... logical (2/2)

Keep the happy path branches consistent!

1: 
2: 
3: 
4: 
5: 
if (isAvailable(product)) {
  if (!isHidden(product)) {
    return getProductPage(product);
  } else return null;
} else return null;

Reduce unnecessary nesting

1: 
2: 
3: 
if (!isAvailable(product)) return null;
if (isHidden(product)) return null;
return getProductPage(product);

Program logic

Encoding logic in a readable way

Use appropriate language constructs

Make sure you're not complicating things

Keep "happy path" through code clear

Do not use unnecessary nesting of logic

Consistent code indentation (1/2)

What is the right spacing and line breaks?

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
if (isAvailable( product ))
  {
    if (!isHidden(product)) {
    return getProductPage(product);
    } else
        return null;
} else
return null;

Compiler ignores whitespace, but humans do not!

Consistent code indentation (2/2)

Follow style of a project or a language; be consistent!

Indent nested code by the same number of spaces or tabs

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
if (isAvailable(product)) {
    if (!isHidden(product)) {
        return getProductPage(product);
    } else {
        return null;
    }
} else {
    return null;
}

Writing useful comments

Are you explaining something you cannot see from code?

1: 
2: 
3: 
// Return product page if product is available
if (isAvailable(product))
  return getProductPage(product);

Also applies to Java inline documentation for methods

1: 
2: 
3: 
4: 
/**
 * Returns the product price
 */
float getProductPrice(Product product)  { /* ... */ }

Comments and whitespace

Making code easy to read and understand

Don't use comments if you have nothing to add

Comments should add history, motivation, context

Use consistent spacing and indentation

Keep nesting and length of functions sensible

Demo: Improving quality of a poor code snippet

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
// Answers a given query
function answerQuery(query) {
  var query_lower = v.lowerCase(query);
  if (v.includes(query_lower, "rain") || v.includes(query_lower, "sun"))
    { return "I do not care too much about weather"; }
  if (!v.includes(query_lower, "football"))
      { return "Sorry Dave, I cannot do that." }
  return "Football is the ballet of the masses."
}

// Handles a say click
function HandleSayClick()
{
  var el = document.getElementById('message');
  var ml = el.value.toLowerCase();
  var cv = document.getElementById('conversation');
  var an = answerQuery(ml)
           conversation.innerHTML += "<p>" + ml + "</p>";
           conversation.innerHTML += "<p>" + an + "</p>";
}
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
// Searches the query for known keywords (rain, sun
// and football) and returns bot's response
function answerQuery(query) {
  var queryLower = v.lowerCase(query);
  if (v.includes(queryLower, "rain") || v.includes(queryLower, "sun"))
    return "I do not care too much about weather";
  if (v.includes(queryLower, "football"))
    return "Football is the ballet of the masses.";
  return "Sorry Dave, I cannot do that.";
}

// Gets message from the user and appends
// it together with an answer to the conversation
function HandleSayClick() {
  var messageEl = document.getElementById('message');
  var messageLower = messageElement.value.toLowerCase();
  var conversationEl = document.getElementById('conversation');
  var answer = answerQuery(messageLower)
  conversation.innerHTML += "<p>" + messageLower + "</p>";
  conversation.innerHTML += "<p>" + answer + "</p>";
}

Maintaining and improving quality

Maintaining code quality

Social approaches

  • Pair programming - all code writing is done in pairs
  • Code reviews - colleague reads code before merging

Technological solutions

  • Compiler - only checks if computer can understand
  • Style checkers or linters - check stylistic errors and suspicious constructs

Improving code quality

Refactoring

Is a code transformation that

(i) Does not change meaning
(ii) Improves quality of code

Test-driven development

  • Red - Add failing test for new unimplemented feature
  • Green - Make it pass using whatever hacks you need
  • Refactor - Improve quality without breaking it

Example of refactoring (1/2)

The name of the function and input argument are poor

1: 
2: 
3: 
function conv(x) {
  return x * 9 / 5 + 32;
}

Improve quality using rename refactoring

1: 
2: 
3: 
function celsiusToFahrenheit(temperature) {
  return temperature * 9 / 5 + 32;
}

Note that we use new name in all calls to conv

Example of refactoring (2/2)

What is wrong with this function?

Comment indicates it does two separate things
In reality it would be very long

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
function printOwing(invoice) {
  printBanner();
  var outstanding = calculateOutstanding();

  // Print details
  print("name: $" + invoice.customer);
  print("amount: $" + outstanding);
}

Example of refactoring (2/2)

Improve quality using extract function refactoring

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
function printDetails(invoice, outstanding) {
  print("name: $" + invoice.customer);
  print("amount: $" + outstanding);
}

function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOutstanding();
  printDetails(invoice, outstanding);
}

Note that comment becomes a function name!

Summary

Code quality

What is code quality and why it matters
More time is spent reading code than writing it
Extreme programming - simplicity & shared understanding

Specific rules for keeping high code quality
Naming variables, upper/lower case, indentation
Keeping logic simple and comments meaningful

Maintaining and improving code quality
Social and technological approaches to quality
Refactoring and red-green-refactor methodology

CO559: Code quality

What you should remember from this lecture

  • Rules for good naming and lower/upper case
  • Keeping logic simple, comments and indentation
  • Refactoring and red-green-refactor


Tomas Petricek
t.petricek@kent.ac.uk | @tomaspetricek

References

Selected chapters from books

Papers and articles