Let’s Start Programming

Our class begins not with theory, not with history, but with actual programming. We’ll get to the theory and the history momentarily (they’re important for sure), but first, let’s program.

Imagine

Let’s imagine a world in which a UFO, in the shape of a classic “flying saucer,” flies over a grassy field on a sunny blue sky day. Programming can enhance our imagination! We can program a device to draw and animate a spaceship. Let’s do this together. That’s right, it’s time for a Code-Along.

A Flying UFO Code-Along

We’ll start in a separate browser window and navigate to the wonderful p5.js Web Editor. The editor provides us with some starter code in the JavaScript programming language together with the p5.js library. Hit the Play button to see what it does. You should see:

 

Okay! That’s a light gray canvas that is 400 pixels wide and 400 pixels high. Better than nothing, but we want a UFO flying over a grassy field on a sunny blue sky day! That’ll be on us. Baby steps first: we’ll begin by changing the background color.

Quick tip: Do your programming Live!

If it isn’t checked already, please check the “Auto-refresh” box above the code window. This way, your program runs as you type, which is generally super convenient.

Modify the code to read:

function setup() {
  createCanvas(400, 400)
}

function draw() {
  background("skyblue")
}
 

If you had checked the auto-refresh box, your program updated and re-ran as you typed. If you didn’t, hit the Play button to see your change. (Then please check that box! You’ll be glad you did.)

setup and draw

The setup function holds code that runs once, at the beginning of the program. The draw function holds code that runs repeatedly, for each animation frame (something like 60 times per second by default). Of course, you don’t have to animate if you don’t want to: after all, a static scene is just an animation where all frames look exactly the same, right?

Drawing

Now let’s draw a green grassy field (a rectangle) and a yellow sun (a circle). The canvas on which we draw has a coordinate system with (0, 0) at the upper-left corner with the x-coordinate increasing to the right, and the y-coordinate increasing downward:

(0,0) (400,0) (400,400) x y

According to the p5.js reference documentation, we draw rectangles by specifying the upper-left corner and the rectangle’s width and height; we draw circles by specifying the center point and the diameter. Colors are set with the fill function. Let’s draw!

function setup() {
  createCanvas(400, 400)
}

function draw() {
  background("skyblue")
  fill("lightgreen")
  rect(0, 250, 400, 150)
  fill("yellow")
  circle(400, 0, 200)
}

It looks like shapes are outlined with thin black strokes by default. We can git rid of the outlines by adding noStroke(). We can add it to setup, since it only has to run once.

Exercise: Add the noStroke() line. How did it go?

Design

Just like artists, craftspeople, and engineers, programmers design by tweaking their work until they get it just right (or close enough). Let's change our createCanvas line to make our canvas wider and shorter:

function setup() {
  createCanvas(500, 300)
  noStroke()
}

function draw() {
  background("skyblue")
  fill("lightgreen")
  rect(0, 250, 400, 150)
  fill("yellow")
  circle(400, 0, 200)
}

Uh-oh. That didn’t go so well. We had built our code assuming the canvas was always going to be 400 x 400 and figuring out a bunch of numbers on our own. Computers are good at math, so they should do the work, not us. Here’s what the designer in us should be thinking:

The programmer in us coverts these ideas to code in the most expressive way we can. You become skilled at implementing your ideas over time by studying prior art, by practicing, and through mentorship. In our code-along, we’re going to use the built-ins width and height, which are bound to the canvas width and height, allowing us to draw relative to the cavas size. In particular:

function setup() {
  createCanvas(500, 300)
  noStroke()
}

function draw() {
  background("skyblue")
  fill("lightgreen")
  rect(0, height*0.75,
       width, height*0.25)
  fill("yellow")
  circle(width, 0, 200)
}

Now no matter the canvas size, the sun stays locked to the upper right corner and the grass takes up the lower quarter. If we want to change our canvas size, we just do it in one place and don’t worry about anything else.

Multiplication

Do you know what multiplication and division are for? Did anyone ever tell you? They are for scaling. Scaling is why we mulitply and divide.
Exercise: Well there is one value that isn’t scaled to the canvas size. What is it? What might be a good expression for it to make it scale with the canvas?

Time to draw the UFO. A couple of ellipses ought to do it. The documentation tells us how to draw ellipses. We’re designing, so trying out different sizes and positions until we get things to look right is just fine. (See why having Auto-refresh checked is such a good idea?) After some experimentation, you’ll end up with something you can put at the end of your draw function. Maybe something like this:

fill("gray")
ellipse(50, 100, 80, 20)
ellipse(50, 90, 40, 25)

Taking Pride in Your Work

Programming, like all forms of writing and performance art, is a way of expressing yourself. Whether you are writing essays, books, screenplays, short stories, résumés, technical documentation, magazine articles, manifestos, conference papers, or graphic novels, you want to communicate clearly to your readers. The same holds true for the programs you write.

What questions might a reader have looking at the code so far? They might ask “What do all those numbers mean?” “Why are there so many numbers?” And “What is all that stuff in the draw function even doing?”

We can get clarity into our code by defining and using our own functions. You may have noticed functions are named blocks of code, like the two built-ins setup and draw we’ve seen earlier. Look how much readable our code is now:

function setup() {
  createCanvas(500, 300)
  noStroke()
}

function draw() {
  background("skyblue")
  drawGrass()
  drawSun()
  drawUfo()
}

function drawGrass() {
  fill("lightgreen")
  rect(0, height * 0.75, width, height * 0.25)
}

function drawSun() {
  fill("yellow")
  circle(width, 0, 200)
}

function drawUfo() {
  fill("gray")
  ellipse(50, 80, 80, 20)
  ellipse(50, 70, 40, 25)
}

Now our code literally says: “To setup our app, create a 500 x 300 canvas and make sure we don’t outline any shapes. When drawing a scene, paint the canvas with the sky color, draw the grass, draw the sun, then draw the UFO.” Details of the way you draw the grass, sun, and UFO, have been factored out into their own functions, so readers looking at the draw function see an abstract view of what it means to draw a scene. This a good thing: abstraction is one of the ways humans are able to deal with complexity.

We still have too many numbers in our UFO-drawing code. We can increase readability by using meaningful names; in programming, we speak of binding names to values. Let’s start by naming a couple things.

function drawUfo() {
  const ufoX = 50
  const ufoY = 80
  const ufoWidth = 80
  fill("gray")
  ellipse(ufoX, ufoY, ufoWidth, 20)
  ellipse(ufoX, ufoY - 10, ufoWidth / 2, 25)
}

These names are called variables if bound with let, or constants if bound with const. Variables can vary (have their values changed); constants are constantly bound to a single value. Constants are more common, and approprite here since we are just naming things. (Later, if we want to animate something, we can always switch its binding to let.)

A bonus: Naming does much more than make code more readable! Another beautiful thing about using the names ufoX and ufoY is that if we changed our mind and wanted the ufo somewhere else, we don’t have to explicitly change the code for both ellipses, we only have to change the values bound to those names and voilà both ellipses will magically move together. We’ve tied the two ellipses into one. As a bonus, these name values make it easier to configure our UFO—its easier to change “settings” than to dig into drawing code to figure out how to reposition or resize things.

Exercise: We could have made our “configuration” more than just the (x,y) position and the width. Theoretically, what else could we have configured?

Animation

The first time our UFO is drawn, it appears at position (ufoX, ufoY). To animate the UFO, we need to change its position. Since the draw function runs repeatedly, we only need to increase the value of ufoX after we finish drawing a frame, so the next frame is drawn with the UFO at the new position, and so on!

We increase the (numeric) value of a variable by a certain amount using the += operator. To increase the value of the variable ufoX by 1, we write:

ufoX += 1

But hang on, we can’t just drop that into our draw function just now, for two reasons: (1) the variable ufoX is buried inside the drawUfo function, so draw can’t see it! In programming-speak, the name is local to drawUfo; we need it to be global in order to use it in both drawUfo and draw. (2) We made the variable const, but since we want to change it, we need let. These changes get it working:

let ufoX = 50

function setup() {
  createCanvas(500, 300)
  noStroke()
}

function draw() {
  background("skyblue")
  drawGrass()
  drawSun()
  drawUfo()
  ufoX += 1
}

function drawGrass() {
  fill("lightgreen")
  rect(0, height * 0.75, width, height * 0.25)
}

function drawSun() {
  fill("yellow")
  circle(width, 0, 200)
}

function drawUfo() {
  const ufoY = 80
  const ufoWidth = 80
  fill("gray")
  ellipse(ufoX, ufoY, ufoWidth, 20)
  ellipse(ufoX, ufoY - 10, ufoWidth / 2, 25)
}

We have animation! 🎉🎉🎉 But we can do better. Making it better is called refactoring. Several things can be improved:

So many issues? Don’t fret!

It is perfectly normal to write working code that is in need of improvement! Sometimes “getting it to work then making it better” is just how programming happens.

But more than this: Expect mistakes. Expect to write code that you did not know could be better. We are all learners. Expect yourself and others to find areas for improvement. Perfection in programming is elusive or impossible anyway. Always take advantage of opportunities to learn and improve.

Improvements

We’re going to continue our code-along in class (sorry, web-only readers).

While you already know enough to make and invoke a moveUfo function, the other tasks require an introduction to JavaScript’s objects for bundling UFO properties together, and the JavaScript if-statement to get the UFO to fly back and forth.

Our completed code-along will look like this:

You can see the entire program here.

Saving and Sharing Your Code

This is a good time to save your work. If you haven’t already, log in (you can first make yourself an account, or just log in via Google or GitHub). Select Save from the File menu. Optionally, you can also click the pencil icon next to the project name to rename your project.

Once you've logged in and saved your work, you will see a Share item on the File menu. The programming culture is generally one of sharing. Programmers are flattered when others use their code and extend it in new ways. Be a good citizen and give away your code for free. Select the Share menu item and grab the value in the “Present” box. Go to this URL in a different browser window, or even a different browser. Send it to a friend so they can admire your work. 🤩

If someone shares their code with you, and you decide to modify their code, that’s great too. Just remember to always give attribution to the original author.

What Did We Do?

Congratulations, you wrote, for your first program, a moderately interesting animation of a UFO, and along the way learned a lot of interesting things about programming. You now:

Now it’s Your Turn

You are now ready to strike out on your own! You are going to make an animation of a plane landing. You are going to be creative. With colors, scenery (forests? lakes? runways? air traffic control towers? and animated sunset, perhaps?), colorful aircraft, interesting landing approaches and effects, maybe even sound.

How will you do this?

You should be able to take all you learned about coordinates, colors, ellipses, rectangles, width and height, and variables and functions to build your plane lander. You will also need to browse the documentation to find new things, such as triangle if you'd like to draw trees, and noLoop which you will call to stop the animation once the plane has landed. Remember, though, that while it’s important to look things up in the documentation and search the web, please ask a neighbor, friend, TA, or instructor whenever it’s taking too long to find what you need.

Do you like to learn from instructional videos?

Consider watching Code! Programming with p5.js, an excellent series of videos by The Coding Train.

JavaScript and P5

There are hundreds of different opinions on the right way to learn programming. Debates about which programming language you should learn first are widespread, but don’t pay too much attention to them. Learn several languages! JavaScript is one of those few languages every computer scientist should know, and there are excellent reasons for learning it first. That’s why we’re learning JavaScript today.

lauren.jpg

Programming languages are concerned with the basics of variables and functions and arithmetic and logic and making basic things happen. The powerful stuff, like graphics, sound, machine learning, and networking, comes in libraries written by others. We made our UFO program using Lauren McCarthy’s awesome p5.js library.

You can read about p5.js, its mission, its goals, and its philosophy, at its home page. You can also reach tutorials, examples, and reference material from the home page, too. p5.js wants to make programming accessible to everyone, especially those interested in the arts. (Perhaps you noticed in our code-along how you can be creative with programming—you don’t require Photoshop or Illustrator or Painting programs to express yourself!) Here's a fan article for the awesomeness that is p5.js. Read the article and follow the links!

p5.js is a fun way to get introduced to programming. It is one of many libraries you will use in your JavaScript programming career.

How Can I Succeed in Programming?

Now that you’ve started your programming journey, it’s time for some tips! How can you be a great programmer and have fun programming? Here are 10 suggestions, in no particular order.

  1. Practice! Because programming is a skill like sports, martial arts, music, or one of the classic trades, you need to practice. Make sure, however, that your practice is deliberate, challenging, and importantly, guided.
  2. Learn about Programming. To get truly great, you need to develop a deep understanding of the foundations, and learn the vocabulary of programming. Speaking of vocabulary, here are a couple terms we’ve skipped, for instance:
    • The thing you create by enclosing text with apostrophes, quotes, or backticks is called a string.
    • Embedding values into a string with ${ and } is called interpolating.
    The terms will become second-nature to you as you grow. Do not fear the vocabulary. Do not fear the science. Internalizing words and ideas will help you become adept at writing beautiful and efficient programs that are concise, expressive, and flexible.
  3. Get used to making mistakes! Programming is not for perfectionists. This is worth repeating: programming is not for perfectionsits. You will make many mistakes per day, if you’ve been programming for over 50 years.
  4. Beware of feelings of not-belonging, impostor syndrome, or stereotype threat. Don’t compare yourselves to others. If you want to be a programmer, you belong. Others may have a different skillset then yours, or have been doing things for longer. So what? That doesn’t mean you can’t contribute. Don’t give up.
  5. Use mentors and teachers, and ask for help! No one can figure everything out for themself. It is a misconception that having instruction robs one of the chance to learn. Don’t know how to do something? Look it up if you can, but asking for instruction is important too! (And as a follow up: don’t hesitate to ask a mentor for feedback when you did figure out on your own.)
  6. Know that you can use programming to contribute to any field or endeavor: to the arts, to social good, to medical technology, to information storage and retrieval, to communication. Computation plays a role in every field.
  7. Know that computers exist to amplify human thought. Write programs to do what you want to do, or help you figure out something you want to learn. It’s not about you learning the computer’s language, but rather about having computers help you do what you want to do.
  8. Hone your social skills! You will be collaborating with other programmers a lot! You’ll work on programs running on multiple computers or devices that are comprised of many millions of lines of code—more than any one person can understand.
  9. Study other people’s work. There is much to learn from prior art and from imitation. These might be interesting:
  10. Embrace tools that assist you in programming. We’ve been using the p5.js Web Editor. This tool has many, many features. You can’t and don’t need to learn all the features at once, but it’s good to pick up some skills as you go. Here’s a video by the creator and lead developer of the editor (made when it first came out, but still useful):

Summary

We’ve covered:

  • Drawing and animation in JavaScript using the p5.js library
  • Variables and functions, and why we need them
  • Ways to make code more readable
  • Ways to make code more resilient to change
  • How JavaScript and p5.js are related
  • Things to know to help you on your way to becoming a great programmer