Refactoring into Functions
Note: Most of the content of this page is inside toggles. Click on the triangles to disclose the code.
-
The initial program
function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { fill("white"); circle(85, 200, 80); fill("blue"); circle(85, 200, 80-30); fill("black"); circle(85, 200, 15); fill("white"); circle(185, 200, 80); fill("blue"); circle(185, 200, 80-30); fill("black"); circle(185, 200, 30); fill("purple"); rect(55, 310, 180, 20); circle(55, 305, 60); circle(55+170, 305, 60); }

-
Use “ablation” to reverse-engineer code
function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { // fill("white"); // circle(85, 200, 80); // fill("blue"); // circle(85, 200, 80-30); // fill("black"); // circle(85, 200, 15); fill("white"); circle(185, 200, 80); fill("blue"); circle(185, 200, 80-30); fill("black"); circle(185, 200, 30); fill("purple"); rect(55, 310, 180, 20); circle(55, 305, 60); circle(55+170, 305, 60); }function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { // left eye fill("white"); circle(85, 200, 80); fill("blue"); circle(85, 200, 80-30); fill("black"); circle(85, 200, 15); // fill("white"); // circle(185, 200, 80); // fill("blue"); // circle(185, 200, 80-30); // fill("black"); // circle(185, 200, 30); fill("purple"); rect(55, 310, 180, 20); circle(55, 305, 60); circle(55+170, 305, 60); }function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { // left eye fill("white"); circle(85, 200, 80); fill("blue"); circle(85, 200, 80-30); fill("black"); circle(85, 200, 15); // right eye fill("white"); circle(185, 200, 80); fill("blue"); circle(185, 200, 80-30); fill("black"); circle(185, 200, 30); // fill("purple"); // rect(55, 310, 180, 20); // circle(55, 305, 60); // circle(55+170, 305, 60); }


-
Capture our knowledge about the program into comments
function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { // left eye fill("white"); circle(85, 200, 80); fill("blue"); circle(85, 200, 80-30); fill("black"); circle(85, 200, 15); // right eye fill("white"); circle(185, 200, 80); fill("blue"); circle(185, 200, 80-30); fill("black"); circle(185, 200, 30); // mouth fill("purple"); rect(55, 310, 180, 20); circle(55, 305, 60); circle(55+170, 305, 60); } -
“Factor out” the code stanzas into functions
function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { // left eye leftEye(); // right eye fill("white"); circle(185, 200, 80); fill("blue"); circle(185, 200, 80-30); fill("black"); circle(185, 200, 30); // mouth fill("purple"); rect(55, 310, 180, 20); circle(55, 305, 60); circle(55+170, 305, 60); } function leftEye() { fill("white"); circle(85, 200, 80); fill("blue"); circle(85, 200, 80-30); fill("black"); circle(85, 200, 15); }function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { // left eye leftEye(); // right eye rightEye(); // mouth fill("purple"); rect(55, 310, 180, 20); circle(55, 305, 60); circle(55+170, 305, 60); } function leftEye() { fill("white"); circle(85, 200, 80); fill("blue"); circle(85, 200, 80-30); fill("black"); circle(85, 200, 15); } function rightEye() { fill("white"); circle(185, 200, 80); fill("blue"); circle(185, 200, 80-30); fill("black"); circle(185, 200, 30); }function setup() { createCanvas(windowWidth, windowHeight); background("pink"); } function draw() { // left eye leftEye(); // right eye rightEye(); // mouth mouth(); } function leftEye() { fill("white"); circle(85, 200, 80); fill("blue"); circle(85, 200, 80-30); fill("black"); circle(85, 200, 15); } function rightEye() { fill("white"); circle(185, 200, 80); fill("blue"); circle(185, 200, 80-30); fill("black"); circle(185, 200, 30); } function mouth() { fill("purple"); rect(55, 310, 180, 20); circle(55, 305, 60); circle(55+170, 305, 60); } -
Now we don’t need the comments. The function names are “self-documenting”
function draw() { leftEye(); rightEye(); mouth(); } -
This only works because we are using descriptive function names
function draw() { f1(); // draw the left eye f2(); // draw the right eye f3(); // draw the mouth } function f1() { // … } function f2() { // … } function f3() { // … } -
Replace repeated constants by variables
function leftEye() { let xCenter = 85; let yCenter = 200; fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, 15); } function rightEye() { let xCenter = 185; let yCenter = 200; fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, 30); } -
Turn the
letvariables into function parameters, that receive their values from where they are usedfunction draw() { leftEye(85, 200); rightEye(); mouth(); } function leftEye(xCenter, yCenter) { // let xCenter = 85; // let yCenter = 200; fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, 15); }function draw() { leftEye(85, 200); rightEye(185, 200); mouth(); } function leftEye(xCenter, yCenter) { // let xCenter = 85; // let yCenter = 200; fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, 15); } function rightEye(xCenter, yCenter) { // let xCenter = 185; // let yCenter = 200; fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, 30); } -
The remaining difference between
leftEyeandrightEyeis the pupil size. Parameterize it too, so that the functions look the samefunction draw() { leftEye(85, 200, 15); rightEye(185, 200, 30); mouth(); } function leftEye(xCenter, yCenter, pupilSize) { // let pupilSize = 15; fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, pupilSize); } function rightEye(xCenter, yCenter, pupilSize) { // let pupilSize = 30; fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, pupilSize); } -
Now
leftEyeandrightEyehave the exact same definition. We could deleterightEyeand useleftEyetwicefunction draw() { leftEye(85, 200, 15); leftEye(185, 200, 30); mouth(); } function leftEye(xCenter, yCenter, pupilSize) { fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, pupilSize); } -
Since
leftEyeis used to draw both eyes, rename it toeyefunction draw() { eye(85, 200, 15); eye(185, 200, 30); mouth(); } function eye(xCenter, yCenter, pupilSize) { fill("white"); circle(xCenter, yCenter, 80); fill("blue"); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, pupilSize); } -
Now it’s easy to add a third eye, by calling
eyea third timefunction draw() { eye(85, 200, 15); eye(185, 200, 30); eye((185 + 85) / 2, 200 - 50, 5); mouth(); }

-
Parameterize the iris color. This allows us to draw the third eye in a different color.
function draw() { eye(85, 200, 15, 'blue'); eye(185, 200, 30, 'blue'); eye((185 + 85) / 2, 200 - 50, 5, 'green'); mouth(); } function eye(xCenter, yCenter, pupilSize, irisColor) { fill("white"); circle(xCenter, yCenter, 80); fill(irisColor); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, pupilSize); }

-
(Optional material, not shown in class) It’s difficult to remember the order of the function parameters. Here’s an alternative, that names them where the function is used as well as where it’s defined.
function draw() { eye({ xCenter: 85, yCenter: 200, pupilSize: 15, irisColor: 'blue' }); eye({ xCenter: 185, yCenter: 200, pupilSize: 30, irisColor: 'blue' }); eye({ xCenter: (185 + 85) / 2, yCenter: 200 - 50, pupilSize: 5, irisColor: 'green' }); mouth(); } function eye({ xCenter, yCenter, pupilSize, irisColor }) { fill("white"); circle(xCenter, yCenter, 80); fill(irisColor); circle(xCenter, yCenter, 80-30); fill("black"); circle(xCenter, yCenter, pupilSize); }
©2020–2022 by Oliver Steele.