Transcript
(Editor's note: transcripts don't do talks justice.
This transcript is useful for searching and reference, but we recommend watching the video rather than reading the transcript alone!
For a reader of typical speed, reading this will take 15% less time than watching the video, but you'll miss out on body language and the speaker's slides!)
Hello. Unfortunately, I don't actually have any slides. So I apologize.
And the reason is because I realized that today was Gary Conf, so I decided to restore my laptop from a back up this morning, and it didn't work.
[LAUGHTER]
I'm just kidding. I don't keep backups.
[LAUGHTER]
So, this is the name of my talk, "I Don't Have Time for This." This is a talk about things I don't have time for, but I would like you to do them for me. And I want to introduce myself first because I think that there are people in the audience that don't know who I am. And the reason I think that is because I tried to AirDrop pictures of my cat to random people, and they turned it down. So---
[LAUGHTER]
Josh and Gang, you should have accepted that.
[LAUGHTER]
So, my name is Tender Love. Well, Aaron, I'm known on the internet as Tender Love. You might not recognize me in person. This is what I actually look like on the internet. I work for a company called GitHub. We do stuff with Git. It is the only legit company out there.
[LAUGHTER]
I have two cats. This is Choo-Choo, or we call her Sea-Tac. Sea-Tac Airport Facebook, YouTube, Instagram, Snapchat now, or Sea-Tac for short.
And this is the more famous cat. This is Gorbachev Puff Puff Thunderhorse the Third. I have stickers of both of these cats, if you want. I actually do. People think I'm joking when I say this. I really do have stickers of them. So if you want one, come say hello to me.
I'm from Seattle. Well, I'm not originally from Seattle. I've lived here for about 17 years. So I say I'm from here. I'm actually originally from Utah, and I want to tell you a little story about Utah.
I was invited to give a talk at a Ruby conference in Utah. And I kept turning them down year after year because I always have to go to Utah for Christmas, and I just don't want to go again. Once a year is enough.
So, one year I thought to myself, well, it would be nice if my parents actually saw what I do for a living. And, like, I talk to my parents every day. Well, not every day-- I talk to them frequently. They're both engineers. It's not weird to them that I do programming, like, I sit at a computer all day. They know everything about what I do for my job. Like I tell them all this stuff.
The one thing that I don't tell them, or that I'd never told them, was my nickname on the internet.
[LAUGHTER]
And so, the organizer e-mailed me. And he was like, yeah, you know, come give a talk at our conference. And I said, yes, I'd be happy to, but only if you give me two extra tickets for my parents because I'd like them to see. And the organizer said, yeah, sure, you know, no problem.
So I go there. We all show up at the conference, meet the organizer, and I say-- I introduce my parents. And he says, oh, OK. You know we've got three seats reserved for you down at the front of the auditorium. And I'm like, OK.
So the three of us go down to the front of the auditorium. And there's three seats and three signs, and-- one on each seat-- and the first sign says "Tender Love." The next sign says "Tender Mom," and the next sign says "Tender Dad." And--
[LAUGHTER]
I'm just like, no! Not right now. Like, this is not a good time. So I had to quickly explain to them. I'm like, OK. You know, people know me by this name. Don't worry about it. It's fine.
[LAUGHTER]
They're going to ask you about it, but it's fine. So, I told-- you know, I consider Seattle to be my hometown now. But I grew up in-- I grew in Utah. And when I was giving this talk, I put a joke in the talk. And the joke landed, but it didn't land the way that I thought it would. So I'm going to give the same joke here.
So when people find out that I'm from Utah, they always ask me the same question, and I have to tell you the answer is no. I don't know how to ski.
[LAUGHTER]
So, people laugh-- people laughed at this joke. And I was like, great. You know, the audience is-- they enjoy the joke. And then several people came up to me after the conference, and they're like, yeah, people ask me all the time if I know how to ski. And I'm like,
[LAUGHTER]
Cool. OK?
[LAUGHTER]
So, anyway, now that Seattle is my hometown, I wanted to share this joke with you. Hopefully it made sense this time. All right.
So, welcome. I want to say welcome to Seattle to all of you from out of town. This is a picture I drew of Seattle.
[LAUGHTER]
I drew this.
[CHUCKLES]
I would like you to support local businesses while you're here. And it's no secret that I'm a fan of supporting local businesses. Like, I tweet about it all the time. I'm really a huge fan of local businesses.
So while you're here, please shop local. Consider shopping at places like Amazon, or Costco is also a good one. I think it's also important that while you're here you try to support local softwares. We have Microsoft. You can go shop there. Or we also have Adobe.
And another neat thing here is if you actually need an airplane, we have a company for that. So you can go buy-- you can go buy-- go buy an airplane.
The other neat thing here is like we have really, really excellent local coffee. So I encourage you to check this out. There's competing brands, though. You might also want to check out Seattle's Best. I heard they're the best.
I want to apologize to Jenn. We don't run on Dunkin. I'm sorry. So we don't have that here. Anyway-- so I'm sorry.
Anyway, I love-- I love supporting local, and I tweet about this all the time. And then I was tweeting about it the other day, and I get this reply from Lord Gary of Sound Studio. He responds to me with just one line that says, you know, sorry about the battery.
And I look at that tweet. You know, I was like, I shop at Amazon because I support-- you can read this. And he says, sorry about the battery. And I'm like, what do you mean?
And then I see, oh, it's a screenshot. And I see that he is searched for every time that I tweet about local businesses. And I'm like, what are you-- what are you trying to do to me? You know that when the battery is at like 12%, this really stresses me out. Why did you--?
[LAUGHTER]
Why did you do this? Just, ugh, terrible. So the only thing that I could think is that he's like sitting there in his sound studio--
[LAUGHTER]
--just sitting there hating on local businesses all day. So enough about Gary. This is not-- this is not Gary Conf. This is Deconstruct Conf. Show my slide. Yeah, there we go.
So I decided to deconstruct something. So I-- as all thought leaders do-- I went to the local Taco Bell, and I picked up a taco and deconstructed it. So you can actually see the different ingredients there. I don't think anybody has done this.
[LAUGHTER]
I also figured out-- I figured out how Gary grouped the speakers. He put all the people with good slides at the beginning.
[LAUGHTER]
Anyway, so I deconstructed a taco there. Then I also attempted to do a seven-layer burrito, and it did not work out so well. So speaking of things that are orange and distasteful, I want to talk a little bit about Hacker News.
[LAUGHTER]
So
So, I read Hacker News, and I'm also a member of a website called Twitter. It's on the internet. You might go there. And a lot of the people whose posts that I read on Twitter, they don't like Hacker News. They always say that it sucks.
But I like Hacker News. And the reason I like it is because they have different comments on there, and I like to read the comments and tell them-- respond to them with things. For example, like the other day, someone was like, oh, I have a post on why Slack is inappropriate for open-source communications.
And I read the post, and I was reading the comments. And the first comment said, we are temporarily in a Dark Age of end user, open-source software. And I thought about this, and I was like, they're exactly right. Because the other day, my friend Justin Searls, he actually got bit by a rat, and he died.
[LAUGHTER]
He died-- he died of plague. We literally are in the Dark Ages. It's terrible.
[LAUGHTER]
The other posts I read said about how Electron is Flash for the desktop, and that Slack uses 5% of the CPU all the time. And I was thinking about that. And I'm like, well, OK. So you have a CPU, and Slack uses 5% of the CPU. Why don't you just get a bigger CPU?
[LAUGHTER]
Buy a bigger CPU, you dummy. I mean, I can't believe this. If Alan Turing were alive today, he would be reading these comments, and just he would be the saddest ever.
[LAUGHTER]
Actually a person-- just Google him on Facebook if you don't believe me. So I was also reading about Hacker News, about language features, and they were saying something about how every single-- every single language needs to have generics. And I believe that they actually got this right.
No generics in your language means that your language is a failure. And the reason your language is a failure is because insurance companies only cover generics. So, if you take your programming language into the hospital, they're just going to reject it. They will not cover that.
So that's all I have to say about deconstructing Hacker News. Anyway, I don't-- I don't have time for this.
[LAUGHTER]
Let's talk about-- OK. Let's move on to the actual talk part. I was going to name it "I Don't Have Time for This," and I thought, well, I don't know. Maybe I'll change the name to "Five Things I Don't Have Time For." But then I got afraid of that.
I decided to change it back to "I Don't Have Time for This" because this title seemed to be much more noncommittal. I didn't actually have to come up with five different things. I didn't want to commit to five things, and it's also a humorous use of a common phrase.
I was filled with fear and self-doubt, especially because Gary told me, oh, there's no pressure. You don't, like, you can talk about anything you want to. The problem for me is when anybody says to me there's no pressure, that means that there's just tons of pressure. It's all the pressure.
What if I can't put together five things? So, the actual real title of this talk is "Some Things I Don't Have Time to Do and You Should Do Them for Me." So maybe three things.
Now, on top of this, Gary asked me for an abstract. And I feel really bad because I didn't give him one. But after watching the talks this morning, that's actually a good thing because I learned that abstractions are bad. So,
[LAUGHTER]
I'm glad I didn't deliver that. Anyway, this talk is a talk about code smells. We're going to talk about code smells.
And I want to show you something. We're going to revisit this graph that I have. I acquired this data. This is really just-- this is crap data. I acquired the data, and I want to do some analysis on this data.
And I've been running it through-- I'm a Ruby programmer. I program many languages, but the main language I program is Ruby. And I had to do some signal processing on this data. And it involves a lot of math. And I just thought to myself, well, maybe I can improve the Ruby virtual machine such that the math will be faster.
Because I actually have a lot of data. I've been recording this data every second since January, I guess January 23. So I've been taking a reading every second since then. And I have to analyze all these data points.
So the first thing I want to talk about is some Ruby VM tricks that I'd really like to do. So first we'll cover how a VM works. The way the Ruby MRI's VM works as we have a program which consists of instructions and parameters. And we also have a stack and a program counter.
So the program counter always points at the instruction that's going to be executed next. So first we'll execute the push statement. That pushes four onto the stack. Then three gets pushed onto the stack. And then add gets executed.
The way that this is actually implemented in code would look something like this. We have a list of instructions. We have a loop. We loop through the instructions. We look up the instruction. We have a table that says, OK, I need to know what function to call for this particular instruction. And then we actually call that function.
So, one thing that we can do to actually speed this up is we can remove this loop by generating our virtual machine. If we change our virtual machine to be generated-- say we take all those functions that handle each of the instructions, and we add a tiny bit of code to the end of that function-- then all it does is look up the next thing to call, and then calls that function.
We no longer need to have this loop anymore. We don't have to jump. We can just keep executing instructions as they come. This technique is called a threaded virtual machine because we're threading the execution of the code through all these functions.
Now, the other thing that we can do is we can eliminate these function calls altogether. So, if we take a look at this code, we're looping over each of these instructions. We're generating- oops. It didn't show the thing. OK.
We're calling a function for each of these instructions. And the problem is our stack is going to grow over time as we execute the program, because we keep calling functions and keep calling them. So the stack gets too large. And we don't want that happening.
So instead what we can do is we can use jump, or as I like to say, a socially acceptable go-to, we look up the place where we need to jump to, and we actually jump to that address rather than calling a function. So this is a technique that we can do. And see, we can't do this in Ruby. I've just written some pseudo code up here for you to look at.
So this part that's actually generated, well, all it does is it looks up the address that we need to jump to, and then it just jumps to that address. So we're able to eliminate those function calls altogether.
Now, we have one other problem where every time we're executing one of these instructions, we actually have to look up the place that we're jumping to we. Have this lookup table. Well, we can eliminate that lookup table as well.
That lookup table, all it does is it maintains a key of the instruction name and a value, which is just a place to jump to. What we can do is we can say, well, when we're actually compiling your code into bytecode, rather than inserting instruction names into the instructions, let's actually just insert the address of the place we need to jump to at the time.
So in this way, we're able to just say, OK. We look up the-- rather than storing the instruction names, we're storing addresses. And we can jump immediately to those addresses. This is what's called a direct-threaded VM.
So it's essentially the same thing. We're threading the code. But it's called a direct-threaded VM because we're storing those instructions directly in the-- or we're storing those locations directly in the instruction sequences.
Now, the interesting thing about this is the addresses are just integers. So it's just some number. And the only thing that keeps us flying off into memory somewhere is that we actually pre-calculated these numbers when we were compiling your code.
So, we could have any address that we wanted to in those locations. It's just that we don't. We limited those to the instructions of the Ruby VM or whatever VM you're actually using.
So what I really want to do is I want to be able to create custom instructions built from machine code at runtime. If we could actually disassemble those, disassemble those virtual machine instructions, and then just insert a number there, our own arbitrary number, we could actually-- we could jump to native code and execute native code at that particular location, rather than executing the Ruby VM code.
So here is an extremely simple example. I want you all to read this code very closely. What this actually does is this assembles machine code at runtime using LLVM. So we can do all of this with LLVM. This assembles some machine code and can execute the machine code. The bit that's missing is it won't insert it into your Ruby instruction sequences.
So the first idea I don't have time for is custom instructions at runtime using LLVM. So back to this data that I acquired. And again, I really apologize. This data is just really crap data. So I'm sorry about that.
But I want to be able to analyze this. We have ideas now for making math faster in Ruby, But I also really need to do some signal processing on this. So in order to analyze this data, I actually need to build a police scanner.
Now,
[CHUCKLING]
I'm 36 years old now, which is ancient for a programmer. I shouldn't have told you my age. And an important part of getting older is that I have to start listening to police scanners. I mean this is--
[LAUGHTER]
We just bought a house. I'm going to sit on the porch with my police scanner. I got to know what's going on in the neighborhood. Come on.
So I bought one of these things. And what it is is it's a USB radio. It's a software-defined radio. And you can pick up one of these on Amazon for like $20.
So it's a software-defined radio. And what that means is you can just plug it into your machine, and you can hook up this program. This program is called GQRX. And if we had sound, you could hear some sound.
And what you're seeing here is a waterfall diagram of everything being broadcast on the signal that I've tuned to, which is 851 point whatever megahertz. And what's cool is you can slide that thing back and forth, and that you can slide the tuner back and forth, and see what's being broadcast on the channels left and right.
Now, that thing that's being broadcast in the center there, that's what's called a trunking channel. This is an actual visualization of the police radios when I recorded this. So that's what's called a trunking channel.
And on the right there, you'll see some other broadcasts that are jumping around. And the way trunking works is essentially it says I'm going to broadcast a digital signal on one frequency, and then that digital signal is going to tell you where any particular channel will be. So say you have a channel one. Channel one might be on some frequency, but it may hop to a different frequency. And this digital signal is the one that tells the radios where they need to hop to.
In comparison, this is an FM band. That's what FM band looks like. So, again, our police scanner looks something like this. We have a digital trunking signal there that we need to analyze. Note those lines over there actually are the analog audio from the police, and you can see that they're jumping around between frequencies.
So in order to do this, we need to talk about digital signal processing. There's two types of signals, continuous and discrete signals. Continuous signals-- are there any Persona players? This is for you.
[LAUGHS]
So continuous signals, imagine a light. It's coming to you all the time, or you're listening to sound. These signals are continuous. Whereas in computers, we have to deal with discrete signals. And what those are is we're essentially just taking points during time.
So if we take two samples, there could be an infinite number, infinite number, of values between those two samples, and we can't really store an infinite amount of data in a computer. So we have to deal with discrete signals. So discrete signals are just a list of points.
So here is a discrete signal that I have. I have a discrete signal, and again, I'm really sorry this is crap data. We were going to clean it up. It's not great now.
Now, the way that we do analyzation on this is we go through a process called convolution. So we use convolution to analyze digital signals. And we're just going to go through some basics of that.
And what convolution is is taking two signals and combining them in some way, in order to come up with a third signal. And the formal definition of it is this math equation, but we're not going to deal with that too much. Essentially-- we'll look at this in code-- essentially what it is is we have two signals, x and h, and we combine them to come up with a signal y.
And the convolution code in Ruby looks like this. We're not going to go through it. Just note that it's based on arrays that have an index of 0. In Ruby, we start indexing at 0. This will become important in a second.
Now, the length of the convoluted signal is the length of those two signals minus 1. The way that we actually do convolution, that equation and code put together, is we take each of the points of the two signals, multiply them together, then add those. And that becomes the new point in our signal and we move along.
So it starts out at 0 and then progresses through the signal. And that's how we calculate our new signal. This is what's called a low-pass filter, and we can apply various low-pass filters to our signals to get interesting signals out of it.
So, for example, this is an identity signal. All it does is you get the same output as you gave as input. We can change this into an amplifier, where we multiply times 2, so it's a louder signal.
We can actually do a shift. So if we move that over by one, we can shift the output signal by one. And if we combine-- if we combine shifting and the other one, which I forgot the name, amplification, we can come up with an echo. So we combine those two together, and we actually get an echo.
We can combine all these in various different ways to get different things. So we can say, like, I want to take an average of-- an average of the signal. And what an average of the signal will do is smooth out anything but keep sharp edges, which is what we want.
So we saw that our graph was a square graph. And this is immediately usable with some applications, like radar. The way it's used with radar is if we have a transmission, on the left side is our transmission, on the right-hand side is the thing that we actually received after transmitting.
We can actually answer the question, does one signal contain the other? And the way that we do that is we take the original signal and convolute that with the signal that we receive. And if the received signal contains that original signal, you'll actually see a spike in the resultant signal like this. So we can detect the signal.
If you take a signal-- another neat thing is we can come up with a Gaussian distribution, if we take one signal and convolute it with itself over and over. So, for example, we'll take a random signal and convolute itself three times. We'll come up with a Gaussian distribution like that. And I just think that's neat.
So again, here is the convolution code. Now, I thought to myself, I would really-- it's pretty simple, and I would really, really like to do this in R, because R is cool. I really like R. It's a neat language.
But I spent many, many hours trying to port this code into R. I wanted to be able to graph this in R rather than export csv's and do all this stuff. I'm like, why can't I just process it in R? We'll do it in R.
So I spent many hours learning R the hard way. And I came to find out that apparently in R, arrays our index 1-based. And the most annoying thing about this is that if you say give me the zero element of the array, it actually returns something to you, which is the type. It's actually the type of that array.
So this one stores in numeric. And the extremely frustrating thing is that you can do math on that type, and it's just fine with it. It's like oh, yeah, it's fine. Whatever.
So I had no-- I was going to swear there. I had no clue what was wrong with my programming, my program. So anyway, this is-- I drew this, too.
So I thought to myself, there must be an easier way. There must be an easier way. I don't want to figure out how to port my algorithm to be 1-based. There's got to be an easier way. I'm not smart enough to deal with 1-based arrays.
So, I took this crap data, and I thought to myself, OK. Well, let's do something that I really enjoy, which is our next idea of things I don't have time for, implementing cons, car and cdr in many different languages, which is something that I do using only lambdas. And we saw this earlier, which is really awesome, and we're going to go over it again.
And the reason, you know, why would I do this? The reason that I do this is that I like learning new languages, but I just don't have much time. So I thought to myself, what is the bare minimum thing that I can do to get endorsed on LinkedIn? And--
[LAUGHTER]
--I figured that the bare minimum that I could do is learn how to use a lambda in any particular language. And if I use a lambda, I can come up with these-- I can build my own data structure. So what are cons, and cdr?
Cons forms a cell. So we take two things, left and right, and it joins those things together. The car function returns the left side of that cell. And the cdr function returns the right-hand side of that cell. And that's really all it does.
So can we implement this only using lambdas? In fact, we can. This is what it looks like in R, node, and Ruby. I program in node, not JavaScript, because I don't know the difference to be honest.
[LAUGHTER]
I had actually tweeted this, and then all these people are like, don't you eat s6, bro? And I'm like, I don't know what you're talking about.
[LAUGHTER]
Anyway, anyway, so what this is is-- what cons is-- is a function that returns a function, and that function takes a function and applies that function.
[LAUGHS]
Don't worry. You don't need to remember this. So, cdr, all it does is it takes a function and calls the function with a function to be applied. So that function that it sends over just returns the left-hand side.
So we saw this earlier, and it's actually really easy to see in R. So we'll call cons-- and we see that when we call cons in the REPL, it returns a function, and that function it actually returns two things, a function combined with an environment. So you see that environment there. And those variables are stored in the environment.
And if we look at car, we see that car is just a function. And we can apply car. We can apply the return value of cons with car, and get our number back. So we can do the same thing with cdr. It's essentially the same, except we're returning the right-hand side.
And using this, we can build a tree of cells like this. We can say, OK, we're going to have these cells linked together, and we'll have a null at the end. On the left-hand side, we'll store some numbers. Using this, we can implement each, which I have implemented here in JavaScript. And we can iterate over an array or a list of con cells using this each implementation.
And what's cool about this is we don't need loops, because we have them here with functions. We don't need a raise because we implemented them with cons, car, and cdr. We don't need hashes because we can calculate hash keys and build a tree out of the-- build a binary tree.
Now, what about numbers? We can also eliminate numbers with functions as well. So we can implement Church numerals like this. So I don't actually need to know numbers. And I don't really-- church numerals, all they are is a function that applies a function that number of times. And at the bottom there, we can prove that that number three, that three function, that applies it three times results in the number three.
And I don't want to build them one at a time like this. So I built up an add. And that adds things together so I can build my numbers, build all my numbers up, without having to define each one of them one by one. So this is called Church encoding, and we saw this earlier today.
So I don't need numbers anymore. I don't need mathematics. I don't need the language to implement mathematics because I can define that. We can do the same thing with logic, which we saw as well. We can implement true false and if. So I no longer need booleans, and I don't need conditionals from your language.
[LAUGHTER]
So, I figure once I learn the lambda it's probably good enough for me to be endorsed on LinkedIn. So again, I have this crap data here. And unfortunately, my algorithm is based on 0-based index arrays.
So what I did is in R, I just implemented cons, car, cdr each, and then each with index. Then I implemented a function that indexes into the array based on a 0-based index. Then I implemented a function that converts R arrays or R vectors into cons cells. And now I have my convolution code in R. And it's exactly the same as the Ruby code.
And this is really great. I'm able to feed in-- I can take my test data. I was able to feed it in, and I could actually plot it. So I took these three plots-- it's OK. It's just test data. We saw this earlier. I was able to feed it into R and then get graphs out of it. I thought this was really nice.
So then I decided to myself, great. This is great. I can show everybody. This will do some signal processing on this, and I'll show it to everybody at the conference. So I took all my real data and input it in, and then it said, "Evaluation nested too deeply. Infinite recursion."
[LAUGHTER]
So, it turns out R does not have tail call recursion.
[LAUGHS]
So things I don't have time for is figuring out R.
[LAUGHTER]
All right. So we have this crap data, and I've been showing you this data that it's you know, it's just not very good. We tried to do some analysis on it, and I want to show you where I actually got this data. I want to show you a contraption that I built.
Basically, what it is is it's a scale, a bathroom scale, with a-- that's a Raspberry Pi. And then we have a Texas Instruments MSP430 up there. So I've got a bathroom scale. The bathroom scale's connected to an MSP430. The MSP430 is connected to a Raspberry Pi. The Raspberry Pi has a motion sensor, and it reads data off of the MSP430. So it gets weight data off of that.
I have it mounted like this. So up at the top there, that blue thing is actually the Raspberry Pi with the motion sensor. It's pointing down. On the bottom there is the scale. That's the scale right there.
Now, on top of the scale, I actually have a litter box. And whenever my cat comes, she gets into the litter box like that, and I'm able to detect that she has entered into the litter box. And I can record the weight at that moment. And then when she leaves, I know the weight after. So--
[LAUGHTER]
If I look at this graph, we can see here on the left-hand side, this is where the cat enters the litter box. Over on the right-hand side, that's where the cat leaves. And if we calculate the difference between the two sides, we can actually figure out how much has been left over in the litter box, which turns out to be approximately 100 grams.
[LAUGHTER]
So I think my time is about up. So I just want to wrap up here with one final thought. And that is that making shit scale is hard.
[LAUGHTER]
[APPLAUSE]
Thank you.