Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>

CO886: Software Engineering
Understandable code






Tomas Petricek

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

Understanding on a small scale

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

Understanding on a large scale

David Parnas (1972)

Conventional
Subroutines follow the order of execution

Unconventional
Modules abstract some aspects of implementation

How to structure large programs

Procedural approach

  • Programs that run top-to-bottom
  • Break program into smaller steps
  • But what data is passed between?

Logical abstraction

  • Identify logical components
  • Hide implementation details
  • How data is represented, stored, ...

Barbara Liskov (1974)

Abstract data types

Programming language mechanism for abstraction

Object oriented programming

Origins of objects

  • Simulating real-world systems
  • World consists of objects
  • Created according to a scheme

Object-oriented abstraction

  • Class defines a template for object
  • Multiple instances of a class
  • Objects hide implementation details

Alan Kay et al. (1972)

Smalltalk

"Actually I made up the term "object-oriented", and I can tell you I did not have C++ in mind."

Galactic scale

Computer made of small computers that exchange messages

Logical structure at a small scale

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

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 structure

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>";
}

Code that fits your brain

Any product that is sufficiently big or urgent to require the effort of many minds thus encounters a peculiar difficulty: the result must be conceptually coherent to the single mind of the user and at the same time designed by many minds.

Fred Brooks (1995 [1975])

DEMO: Fun 3D
www.fun3d.net

Functional programming abstractions

Domain-specific languages

Object-oriented model of shapes

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
class Shape {
  abstract public void Render(Scene scene);
}
class Combine extends Shape {  
  public void Render(Scene scene) {
    s1.Render(scene);
    s2.Render(scene);
  }
}
class Cube extends Shape {
  public void Render(Scene scene) {
    // Render cube onto the scene
  }
}

Two ways of modelling 3D worlds

Object-oriented class hierarchy

Functional algebraic data type

1: 
2: 
3: 
4: 
type Shape =
  | Cube
  | Move of Shape * float * float * float
  | Combine of Shape list

Two ways of modelling 3D worlds

Object-oriented class hierarchy

  • Abstract method in the base class
  • Implementation in each shape
  • Easy to add new shapes

Functional algebraic data type

  • Separate data from functions
  • Render function handles all cases
  • Easy to add new operations

Domain-specific languages

Motivation: When do we need this?

  • Repeated problem, many variations
  • User stories, game logic, contracts
  • Accessible to non-programmers

Solution: Build a language for a given domain!

  • External – New language with custom syntax
  • Internal – Library in an existing language

Domain Specific Languages (DSLs)

Model
What we work with? How does it compose?

Syntax
How can we write it in a human-friendly way?

Functional and object-oriented DSLs

Functional languages
Custom operators and function composition

1: 
2: 
(Fun.cone |> Fun.color Color.red) $
(Fun.cylinder |> Fun.move (0, -1, 0))

Object-oriented languages
Fluent interfaces and the builder pattern

1: 
2: 
fun.cone().withColor(color.red).
  combineWith(fun.cylinder().moveBy(0, -1, 0))

From objects and beyond

Many ways to express problems in code

Object-oriented - decompose into entities

Functional - separate data and functions

Domain specific languages - for a specific problem

Event sourcing - state as a list of events

Microservices - system as independent servers

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

Code smells

Hints that code has poor quality

Long parameter list (bloaters)

Switch statement (OO abuse)

Speculative generality (dispensables)

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

Understandability on small and large scale
Keeping the happy path clear
Conceptually coherent code structure

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

CO886: Understandable code

What you should remember from this lecture

  • The idea of a happy path
  • Conceptual coherence of structure
  • Refactoring and red-green-refactor


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

References

Academic papers

Tools, books and articles