Tip:
Highlight text to annotate it
X
So, unlike the previous session, I don't have any prizes to give out.
I'm just going to tell you how to live your life.
This talk is actually about a way of living your life that most people don't talk about.
As you approach your career, you'll hear a lot about following your passion,
or doing something you love.
I'm going to talk about something kind of different.
I'm going to talk about following a principle,
—finding a guiding principle for your work, something that you believe is important
and necessary and right, and using it to guide what you do.
There are three parts to this talk.
I'm first going to talk about the principle that guides a lot of my work,
and try to give you a taste of what comes out of that.
And, I'm going to talk about some other people that have lived this way;
what their principles are, what they believe in.
But these are all just examples, to help you think about what you believe in,
and how you want to live your life.
So to begin with me: Ideas are very important.
I think that bringing ideas into the world is one of the most important things that people do.
And I think that great ideas, in the form of great art, stories, inventions, scientific theories,
these things take on lives of their own,
which give meaning to our lives as people.
So, I think a lot about how people create ideas and how ideas grow.
And in particular, what sorts of tools create a healthy environment for ideas to grow.
Now, I've spent a lot of time over the years making creative tools, using creative tools,
thinking about them a lot, and here's something I've come to believe:
Creators need an immediate connection to what they're creating.
So that's my principle.
Creators need an immediate connection to what they create.
What I mean by that is when you're making something, if you make a change,
or you make a decision, you need to see the effect of that immediately.
There can't be a delay, there can't be anything hidden.
Creators have to be able to see what they are doing
So now I'm going to show you a series of cases where I noticed that principle is violated
And I'll show you what I did about that.
And then I'm gonna talk about larger context, in which I do this work
So, to begin with, let's think about coding.
Here's how coding works: you type a bunch of code into a text editor,
kind of imagining in your head what each line of code is going to do.
And then you compile and run, and something comes out.
In this case, this is just JavaScript, Canvas, and it draws this single little tree.
But, if there's anything wrong with the scene,
or if I go and make changes, if I have further ideas
I have go back to the code,
and I edit the code, compile and run,
see what it looks like.
Anything wrong, go back to the code.
Most of my time is spent working in the code, working in a text editor blindly,
without an immediate connection to this thing,
which is what I'm actually trying to make.
So I feel that this goes against the principle that I have,
that creators need immediate connection to what they're making,
so I have tried a coding environment that would be more in line with this principle.
So what I have here is a picture on the side, and the code on the side,
and this part draws the sky and this part draws the mountains
this draws the tree,
and when I make any change to the code
the picture changes immediately.
So the code and the picture are always in sync; there is no compile and run.
I just change things in the code
and I can see the change in the picture.
And now that we have this immediate connection between
the code and the picture,
we can think of ways of changing the code other than typing. ...
So, for example, this number here is the length of the branches
So if I want to control that number, I just point my mouse to it,
hold down my control key, and I can dial it up and down.
So I can see what it looks like for big branches or small branches
and I can converge on what feels right to me artistically.
And this works for any number in the code
So I just point to it and dial up and down
And some of these numbers here, I know what they do
But still kind of surprising to see them do it [chuckles]
And other ones are just completely surprising
[chuckles]
So down here, I've got
this for loop where I'm counting to sixteen,
I'm putting sixteen little pink blossoms on every branch.
And I can turn it down for less blossoms or turn it up for more.
But, look at what I'm doing here:
I'm just moving that number up and down around twenty or so:
and it has this really interesting shimmering effect;
it kind of looks as if the wind is blowing through the tree.
And the first time I saw this I immediately started thinking about
how I could use this effect for an animation.
How would I ever have discovered that if I had to compile and run between every change?
So much of art, so much of creation is discovery,
and you can't discover anything if you can't see what you're doing.
So I've shown you adjusting the code, let's add some code.
I'd like to put a sun up here in the sky,
so I'll go to the drawSky function,
and I want to fill in a circle,
so I start typing context.fillCircle,
and as soon as I start typing I get this autocomplete list
of the different fill methods.
So these are the things I can type there: fillCircle, fillRect, fillText.
And as I move up and down this autocomplete list,
I immediately see what each of them is doing.
So, I don't have to imagine what it would do from the method name.
I don't have to look at the documentation,
I just see it, immediately.
So I want a circle,
and I'm going to adjust the x coordinate
and the y coordinate,
change a radius a bit...
And that looks about right.
Probably should be yellow,
so I'm going to set the fill style.
Context.fillStyle, same autocomplete as before,
choose fill style
gives me white by default,
and I can change that color code the same way I change any number,
I hit the control key, and I get a color palette.
So I can choose a nice yellow for my sun.
Although, the white was kind of interesting, I thought.
I kind of didn't expect that. But,
with the white, it now looks like the moon instead, right ?
Hey, look, it's night time. [chuckles]
So having this immediate connection allows ideas to surface
and develop in ways that would be impossible before.
But there's still a problem here, I think.
Which is - I've got this picture,
and I've got this code over here
and I have to maintain a mapping between the two in my head.
So I've got all these lines of code,
and just looking at this line I don't immediately know what it does.
So here's what I can do.
I can hold down the option key,
my cursor changes to a magnifying glass,
and now as I roll over each line of code,
it's highlighting in the picture
what's being drawn in that line.
So, if I want to know what's going on in this function,
I just kinhd of roll down the function and see what highlights.
So here I've got two calls to drawMountain; I don't know which is which;
well, here's that mountain, and here's that mountain.
And this has to work the other way too;
if I see part of the picture,
I need to know what code was responsible for drawing it.
So I do the same thing; I hold down the option key,
and now as I move over each pixel of the picture,
you'll see on the right
it's jumping to the line of code that drew that pixel.
So that drew the sky, and that drew the tree
That drew the blossom
So this is really important to make that mapping
But it is also real useful for navigating around
So, I want to make sun a little bit bigger.
So I jump there, make it a little bit bigger
I want to bring up a tree a little bit,
so I jump there, bring up a tree a little bit
I want to bring up the mountains a little bit.
I jump there, bring up the mountains a little bit
And I can make these changes as quickly as I think of them
And that is so important to the creative process -
to be able to try ideas as you think of them
If there's any delay in that feedback loop
Between thinking of something and seeing it, and building on it
Then there is this whole world of ideas, which..
which will just never be...
These are thoughts that we can't think...
Ideas are very important to me.
And the thing about ideas, is that ideas start small.
Ideas start out, tiny, weak and fragile.
In order for ideas to develop and mature,
ideas need an environment
where the creator can nurture them.
Kind of take care of them, feed them, and shape their growth.
And to me, that's what the principle of immediate connection is all about.
And because ideas are so precious to me,
when I see this principle violated,
when I see ideas stillborn or stunted because their creator couldn't see what they were doing
I feel that's wrong.
And not wrong in the sense of
violating some UI guideline or going against a best practice, but
wrong in a deeper sense than that.
And I'll come back to this, but I want to show you another example of following this principle.
So, in this code here, there is no state
There is no time, there is no interactivity.
And I was thinking about how we would handle those aspects of coding
in a way that's inline with this principle that I have,
that creators need an immediate connection.
So, what I have here, is a little platform game.
Here is my little guy, he can run around, he can jump,
he can die [chuckles].
And the code for him is over here.
So this code makes him run around,
this makes him jump,
this makes him collide with things...
and down here, I've got some code for this little turtle.
And this turtle is not doing much right now
because I haven't finished writing this code,
so, I'm just going to do that right now.
So on each tick, x position plus equals his direction
times the time interval one sixtieth of a second
times some speed,
which, um, I dunno? Could be fast, could be slow
if it's negative, he walks backwards. [chuckles]
And these are all ideas, I can use for other enemies
but I think turtles are supposed to be slow,
so let's set a good speed for a turtle
And then up here, I've got some code that says:
"When my guy, collides with the turtle, he gets some Y velocity".
So it bounces into the air and the turtle gets stopped.
So that looks like that.
And the the turtle gets up after a bit.
The problem is, I don't want the player to be able to get up there yet.
I want the player to bounce up the turtle,
and go through this little passageway down there.
It'll have to go around and solve puzzles and whatnot,
to come back and get the star.
So, the turtle is too bouncy right now.
Now of course I could just turn that down in the code,
and now I can try it
but, but now it's not bouncy enough.
So while it's nice that I can adjust the code while it's running,
without having to stop and recompile and find that place again
I can't immediately see what I need to see,
which is whether or not I make that jump.
So here's what I'm going to do.
I'm going to bounce off the turtle,
and pause the game.
So I pause the game, and now there's a slider up here,
which lets me rewind through time.
And now, I could rewind to back before I made the jump,
and change the code, make it less bouncy
and now when I move it forward,
it's going to simulate it, using the same input controls,
the same keyboard commands as before,
but the new code.
[applause]
This is not good enough. [laughter]
I need to be able to see the changes immediately.
I need to be able to see immediately
whether or not my bounciness is correct.
None of this stuff.
And if you have a process in time,
and you want to see changes immediately,
you have to map time to space.
So here's what I'm going to do.
I'm going to bounce off my turtle, pause the game,
and now hit this button here,
which shows my guys trail.
So now I can see where he's been.
And now when I rewind,
this trail in front of him, is where he is going to be.
This is his future.
And when I change the code, I change his future. [gasps]
So I can find exactly the value I need,
so when I hit play, he slips right in there.
[applause]
So, creators need to be able to see what they're doing.
If you're designing something embedded in time
you need to be able to control time.
You need to be able to see across time,
otherwise you're designing blind.
As I was playing with this, I noticed it's fun to play with gravity.
So I can make gravity a little negative and he starts to float up in the air. [laughter]
And I can kind of play with that and try to get him to stay there.
And you could probably make an entire game around just the mechanic here - gravity manipulation.
In fact, I bet I could fiddle with any part of this code and come up with an idea for a game.
Even if I just comment out the first statement in the code,
now my guy can't move left - he can only move right.
Which sounds kinda silly, but
Terry Cavanagh actually made a beautiful game
around that concept called "Don't Look Back".
Terry Cavanagh, he made another really wonderful game
which you might have seen, called "V", spelled as the letter v six times.
And, the way that game works, is that you can't jump.
Instead, you can only flip upside down,
and you fall up instead of falling down.
So it kinda works like this.
You can walk on the ceiling or you can walk around on the ground.
And so you have these levels, which kind of look like this
And you kind of walk around and you have to learn how to navigate turning like this
And so if you have like, something like that, you won't be able to jump over
You'll have to like flip over and flip over
And he got an amazing amount of game play out of this concept
So again, being able to try ideas as you think of them.
This example, and the last one with the tree,
these are both very visual programs;
we're able to see our changes just by seeing how the picture changes.
So I was thinking about, how we could do more abstract coding
that's more in line with this principle.
How can we write a generic algorithm in such a way that we can see what we're doing.
So as an example, let's take a look at binary search.
Super quick refresher on how binary search works:
you have an array of values that are in order,
and you have a key, which is the value you're trying to locate within the array.
And you keep track of two variables, which are the lower and upper bounds
of where you think that value could possibly be;
right now, it could be anywhere.
And you look right in the middle of that range -
if what you find is too small, then the key has to be after that.
Look in the middle of the range,
if what you find is too big, the key has to be before that.
And you kind of keep subdividing array into intervals
You narrow in on value you're looking for
And in code, binary search looks like this
And from my perspective, you can't see anything in here
Can't see anything. I see the word array, but I don't actually see an array
And so in order to write code like this, you have to imagine an array in your head
And you essentially have to play computer.
You have to simulate in your head what each line of code would do on a computer
And people that we consider the skilled software engineers
are just those people that are really good at playing computer
But for writing our code on a computer
why are we simulating what a computer would do in our head ?
What isn't the computer just do it and show us ?
So. Let's write binary search.
function binarySearch, takes a key and an array.
And then over here on this side, it's saying
"Ok, it takes a key and an array, such as what?
Give me an example; I need something to work with here."
So, for instance, my array might be 'a', 'b', 'c', 'd', 'e', 'f'.
And let's say for instance we're looking for the 'd'.
So now let's start coding.
The lower bound starts out as zero.
Over here it says 'low = 0', nothing amazing there.
Upper bound starts out at the end of the array, so 'high = array.length - 1'.
And over here, it says 'high = 5'.
So I have my abstract formula in the code.
Over here, it's giving me the concrete value
corresponding to these example arguments.
So I don't have to maintain this picture in my head;
it's just showing it to me.
So now I need the index in the middle of the array,
so I'm going to take the average of those two.
'mid =(low + high)/2', and...well that's obviously not right.
2.5 is not a valid array index. So I guess I need to round this off.
So I'm going to add the floor function and it rounded it down to 2.
And I caught that bug literally the second I typed it, instead of writing an entire function and twenty unit tests.
So now I get the value out of the array...
and then I need to subdivide my range,
which, so this if statement which I'll just paste in here.
So in this case, the value I found is less than the key,
so it's taking this first branch of the if statement.
This is adjusting the lower bound.
Of course if the key was smaller, then
it would take this branch of the if statement and adjust the upper bound.
Or, if the key was 'c', then
we would've just happened to find it on the first shot, and we'd return the index.
So this is the first iteration of this algorithm.
And now what we need to do, is loop.
We've subdivided the array, we need to keep subdividing
until we narrow in on what we're looking for.
So, we need to loop; I will just loop.
while 1, do all this.
And now what we have are three columns
corresponding to three iterations of this loop.
So this first column here is exactly what you saw before:
low and high span the entire array, we found a 'c', it was too low,
so we adjusted our lower bound, and loop up to here.
Second iteration, bounds are tighter; we found an 'e'.
We adjust the upper bound.
Third iteration, loop up to here; low and high are the same.
We've narrowed it down to a single candidate -
it's indeed the key we're looking for,
and we returned this index.
So there's nothing hidden here;
you see exactly what the algorithm is doing at every point.
And I can go up to here and try different keys,
so I can see how the algorithm behaves for these different input arguments.
And by looking across this data,
I can develop an intuition for how this algorithm works.
So I'm trying different keys here, and say I try looking for a 'g'.
And this looks a little different. It's not actually returning.
And the reason for this is, I'm looking for a key which is not actually in the array.
And the only way of breaking out of this loop, is by finding the key.
So it's kinda stuck here looping forever.
So we can take a look at this and see what went wrong,
where's the algorithm going off the rails.
These first few iterations look fine,
but this iteration looks weird,
because low is greater than high.
Our range is completely collapsed.
So if we get to this point, then we know the key can't be found.
So I see this faulty condition, and I say, "Oh, that's not right; low has to be less than or equal to high."
Okay, well, I'll just put that over as the condition for my while statement.
'low