Conf42 JavaScript 2022 - Online

Feedback and the REPL

Video size:

Abstract

Programmers have been always been subject to feedback loops. Fast feedback liberates us to do our best work, and slow feedback punishes us. To help us understand our predicament, a brief history lesson is given. This is followed by a demonstration of the REPL, an interactive programming tool. Though widely neglected, the REPL has the potential to make us all happier and more productive.

There will be something in this talk for programmers of any language or skill level, but note that the demonstration is in JavaScript.

Summary

  • Jamaica real time feedback into the behavior of your distributed systems and observing changes exceptions. Errors in real time allows you to not only experiment with confidence, but respond instantly to get things working again. James explains how to get fast feedback in Javascript.
  • John McCarthy came up with Lisp, which is a much higher level language. It has a whole bunch of features that we totally take for granted. A language missing any of these features is pretty handicapped these days. Anything that's true for Lisp is essentially true for JavaScript.
  • Use the repl to write a module. For every component I write, I write a demo. This is called RePL driven development. It gives you better portability. Another thing that's neat is that you get better feedback loops.

Transcript

This transcript was autogenerated. To make changes, submit a PR.
Jamaica real time feedback into the behavior of your distributed systems and observing changes exceptions. Errors in real time allows you to not only experiment with confidence, but respond instantly to get things working again. Close hello, my fellow javascript. My name's James, I'm a programmer, I work with my family, we make apps for horse riders. My sister's the designer, my dad's the Sysadmin, I'm the programmer and my mum's the boss. Now, I'm going to be talking today about the feedback loops that we experience as programmers. So I reckon this is a pretty typical feedback loop for a web developer today. So you might start off changing some code, then you save the file you're working on, rebuild your application. If you're lucky, only the part of the application you've been working on will get rebuilt because that'll be faster. Reload the page because you need to be working on the latest code, right? And again, you might be lucky, it might only reload the portion of the page that you've been working on. And then you need to have a test, have a poke around, see if what you did worked. You might run some automated tests as well. And then you have to figure out if things didn't go well, what mistake did you make? And there'll be a period of debugging and that will usually lead you back to changing more code. Now the steps here can pretty easily be divided into doing steps on the left and waiting steps on the right. So the build and the reload are waiting steps. And when you start a brand new project, you don't even notice the waiting steps. They finish so fast, right? But that doesn't last because as your application grows, as you add more work to the build chain, you do start seeing delays. At first they're just subsecut delays, but they can get longer and longer. And in worst case scenario, you can end up spending more time waiting than doing. So why is slow feedback a problem? Isn't it nice to have a break, relax our mind while we work? Well, I don't think so. I think feedback should be fast for three reasons. One, programmers are creative people, and like artists, we respond really badly to tedium and boredom, right? So a slow testing loop, a slow testing step, a slow build step, breaks our concentration and takes us out of the zone. And the zone is where we want to be, right? That's where we do our best work. Two, it can be really difficult to predict the consequences of changing a piece of code. And that's why it's safer to make our changes in small increments and get feedback each time. A slow feedback loop encourages us to make a lot of changes all at once and then see if what we did worked. And what that does is obscures our mistakes because we've touched a whole lot of the code base and it's no longer obvious where we've made our mistakes anymore. And that just leads to more time debugging. And it's really the worst kind of debugging because no one's going to thank you for fixing a bug that you created 15 minutes ago, are they? Lastly, we want to finish our day with a sense of accomplishment, and it's hard to feel like that if you spent a lot of your day just waiting around. Now I'm going to show you a way to get really fast feedback in Javascript, but first I'm going to tell you a tale. Before the 80s, before the microcomputer revolution, before everyone had personal computers, computers were big, sometimes taking up a whole floor of an office. They were slow, maybe thousands, million times slower than computers today. They could only really do one thing at a time. And they were astronomically expensive. Because they were so expensive, the organizations that ran these computers and paid for them were very reluctant to let them sit idle ever right. So the name of the game was keeping utilization at 100% as much as possible. Like keep those computers burning 24 hours a day, seven days a week to try and get your money's worth. And the way that they achieved this was through this thing called batch processing, where you would create a batch job out of several different programs instead of running them separately. So you might get, say ten programs and stitch them together like first program, second program, third program, fourth program, and feed that batch job into the computer. The computer would churn away work at the first job, spit out the output, move on to the next one, burn away at that. And when all of the batch job was finished, a human operator would come in and they would put in the next batch. And this cut down on handler time. Operator Handler time was very efficient. The people that paid for the computers loved batch processing because they really felt like they were getting their best bang for their buck. But guess who didn't love batch processing? The programmers. Us. The reason it sucked for programmers is that you had to compete for computer time with all of these other jobs. So like there might be a payroll job that calculated everyone's pay for the company, they might be crunching some numbers, and you just want to debug your program, you just want to run it to test it, and you have to submit it along with this batch job, wait hours, possibly days. It wasn't unusual to have a 48 hours turnaround for batch jobs, so made it a real pain to test your code. Now we're not doing batch processing much anymore, or barely at all. So what happened? Well, pretty early on, there was a synergy forming between computing and telegraphy. So telegraphy is the long distance transmission of textual messages by electronic means, right? So nothing fancy, just text messaging, like we do all day, every day now. And the way telegraphy used to work is you would stroll into your telegraph office, and you would pay some money to send a short text message, and they would take your text message and hand it to an operator sitting at a teleprinter. A teleprinter, as you can see in this photo, is sort of. It is what it looks like. It's an electric typewriter hooked up to a phone line, and the operator would dial up some other operator somewhere in the world who also had a teleprinter. And when they connected, your operator would type out your message, which would be printed but in front of the other operator, and they would slice off your message, and it would be hand delivered to the recipient. Now, these machines were used for a long time for human to human communication like this, way before computers. But in 1955, someone had the bright idea to hook one of these computers up, to hook one of these teleprinters up to a computer. And that's where we got the first command line interface. Now, one programmer who saw the potential of this interface was John McCarthy, and he had this incredibly visionary thing to say in 1959. Suppose that the programmers has a keyboard at the computer. So the programmer, not the computer operator, the programmer. Then they can try their program, interrogate individual pieces of data or code, to find an error, make a change, and try again. So what he's describing here is basically interactive programming. So programming with a fast feedback loop where you can just really delve into what your code's doing. The only problem with this vision was that at the time, 1959, no one could afford to use computers like this, because recall that computers were very, very expensive, and they could only do one thing at a time. And if that one thing was interactively programming, that was a huge waste of that computer's time. Because if you think about it, when you program, you spend most of the time thinking. You spend a bit of time typing, and you spend barely any time at all actually running your program. So, in effect, that mainframe would have just been sitting there idle the whole time. John McCarthy's genius idea was that if you had enough programmers all working on a computer at the same time, then that time you spent thinking or typing would cancel that with someone else running their code, and you could end up having a reasonably high utilization of your computer. And John McCarthy called this idea timesharing. And his team developed the first timesharing system. So essentially the first computer that could do loops of things at the same time. And he did that in 1962, and it was big hit with universities and stuff. But since then, the idea of timesharing has exploded. The Internet is timesharing. The idea of having a server that talks to multiple clients at the same time is a form of timesharing. If you've heard of AWS Lambda functions, that's just timesharing. Amazon's just trying to get the most out of their hardware there. So another great invention that John McCarthy had was the Lisp programming language. John McCarthy was an artificial intelligence pioneer. He was one of the first people working on AI, and that means he has in the business of writing smart programs. And they were having trouble doing that with the languages they had at the time, right? So they had Fortran, which was basically for scientific number crunching. They has COBOL, which was a sort of business money oriented language that is good at producing reports and stuff, but they were struggling to model intelligence in these sort of clunky old languages. So John McCarthy came up with Lisp, which is a much higher level language than those other ones, and it has a whole bunch of features that we totally take for granted. A language missing any of these features is pretty handicapped these days. And so the features that appeared in Lisp for the first time in a high level language were conditionals. So like if else also in JavaScript we had the ternary operator. That's a kind of conditional. You don't even want to know what they were doing before conditionals recursion. So a function can call itself by name first class functions. So functions can receive other functions as arguments, and we use that all the time in JavaScript. When you register a callback or register an event listener, the fact that you're passing a function in has an argument that makes it a first class function, a listpad garbage collection, which was really cool, really neat idea. Instead of the programmer having to manually manage their memory and remember to release memory here and there, when they were no longer using it, the computer just looked after that. And that freed up these Lisp programmers to focus on what they were actually trying to do, which is model intelligence. And lastly, Lisp had the repl, and I'm going to talk a bit more about the repl, but I just want to point out that JavaScript has all five of these features, so anything that's true for Lisp is essentially true for JavaScript. So the repl is named after the functions in this very short lisp program. So if you're not familiar with Lisp, each matching pair of parentheses is a function call, and I've color coded them here to make it a bit easy to read. So let's walk through what this program does. The first thing that happens is the read function is called with no arguments, and that sends a prompt to the user's teleprinter and waits for them to type in some source code. When the user's done, they press return and read returns that source code to eval. Now, eval evaluates the source code, it runs the source code, and it returns the resulting value. That value is passed to print, which prints that value out textually to the teleprinter. And when print is done, loop sends us back to read, read eval, print loop repl the best way to understand how the repl works is to see it in action. And as Javascripters we are blessed with a proliference of repls. In fact, every modern browser has a repl in it, and it's super easy to bring it up. I'll just do it right here. I'm just going to right click anywhere on the page, press inspect, and we get the devtools. Now I'm in chrome here, but it's a very similar way if you're on Firefox or Safari, and we want the console tab. That's where your logs and errors get spat out. And down the bottom, beneath all your logs and errors, there's a prompt, and that's where you can type in your source code to be evaluated. Here we go. We can also evaluate functions, and we can evaluate functions that have side effects as well. So we'll do a little hello world. Notice we got two results here. We had the hello world being printed. That was the first thing, but then we get undefined, and the reason we get undefined is that hello world was the side effect. But console log returns undefined. The thing about the repl is you always get some value back, even if it's just undefined. And we're hooked up to the page here so we can access the Dom. So I'm going to use the repl to give this slide a little bit of historical accuracy, because after all, we didn't get lowercase until the late 60s. Because we're interacting with a living running page, we can also schedule tasks for future execution. So if I pass set timeout, a function, in this case the log function, we're going to ask for log to be called with a string in 5 seconds. Set timeout returns a timer id, which we can use to cancel the job, and then it prints out our string. So the great thing about the oracle, great thing about the repl sorry, is it's a form of oracle, so we ask it questions and it gives us answers. And that's really handy for a language like JavaScript, because, well, I mean, it's no secret that Javascript was designed in ten days, didn't get everything right, actually got a lot of things wrong, and it's vital having a way to sort of check out language features before you go and put them in your program, where they might cause horrible, hard to debug problems. For instance, JavaScript has this y two k, but I'll show you it. So we're going to ask the current date what its year is, and we get back just a completely nonsensical answer. So what this method was intended to do was give us a two digit year, but what it does in reality, and this is what the JavaScript specification says it does, is it returns the number of years since 1900, which is insane. JavaScript was designed in 1995, so that meant the date function was going to work for five years. Interestingly, it's not actually JavaScript's fault as such. If you look at Java, Java has a date object, which has a get year method, which does exactly this. And the only reason this is in JavaScript is because Java did it first, and JavaScript had to copy some superficial things from Java. Right now, everything, all the code I've typed in so far has been very low level, and that's because all we've really got to work with here are features of the language, like numbers, math, random, and features of the runtime, like the document object and anything that we've declared via the prompt. So I could declare a variable or define a function and then call that later on. And that might have been all right. It might have been all right to just have this low level kind of repl in the 60s when people were still writing their programs on paper, but it's not really compatible with how we write applications today. So these days we split up our application into modules, and we store these modules in files and we edit them with a graphical text editor we're not using teleprinters anymore and it's not entirely obvious how we're supposed to sort of get our own code, our own modules or our third party modules into the repl so that we can play around with them. One thing you might think of doing is copying and pasting stuff into the prompt, and that will sometimes work. It might work for small things, but if you try to paste a whole module in there, it's going to blow up. You should not allowed to have an import statement or an export statement in the repl in this repl anyway. I was quite surprised to learn a couple of years ago that this problem has been solved for almost 50 years, right? So when Lisp programmers first got computers with screens, they realized that they weren't doing this teleprinter thing anymore and they adapted. And I want to show you what their solution looks like when applied to JavaScript. So this is a garden variety text editor vs. Code. And I've got a plugin installed so that when I press in keyboard shortcuts, source code gets sent to a repl in the background and returns back here. So don't worry. But that webull lost for now, so we can do all the old favorites, we can log, we can even blow up if we want. There we go, error, boom. And because we're still hooked up to a browser, we still have access to the document object. Let's run that. So we just modified the document there so we can do everything the other repl could do, but with more convenience because we're in our text editor where we actually write our code, but we can actually go one step further. This repl supports modules, so I'm going to report view, which is the Javascript library for doing user interfaces. There we go, we'll import that now, we'll see what we got, we'll see what that version member holds. There we go, we're working with view 3.2.30 been. So this is pretty epic. All of a sudden we can just start importing modules and playing with them as if they're low level features of the language, which is awesome. One thing that we can do with this new fanpower is use the repl to write a module. So I'm going to write a component using the repl. This is called RePL driven development. First thing I write when I start writing a module is a specification just in, just in plain English. So in view, a prop is like a parameter for the component, right? So now I've got a specification it's good to write some kind of test. It's good to write the test before the implementation because then you get to actually test the test. Now there's two ways of testing UI components. You can either test automatically or you can test manually. When you test automatically, you have to simulate a human, which I think is really hard. So what I'm doing instead of automated UI testing these days is just for every component I write, I write a demo. And that makes it super easy to play around with the component, debug it, see how it works. So this is how I'd write a demo for view component. Now, we haven't ridden our polite component yet, so that's obviously going to fail when I evaluate it. And just going to mount this single component app to the body element. All right. Now to run this demo, all I do is select the entire module and evaluate it. That fails with a reference error because polite component is not defined. But we can fix that by implementing the component. So a view component consists of a props property. That's where we list loops and a setup function. Now the setup function is called whenever a new instance of the component is instantiated. And this is where we can do all our one time setup work, but we don't actually have any to do right now. So we're just going to go ahead and return a render function. So the render function is essentially called every time the props change. And it's responsible for returning a tree of dom elements to be rendered on the page. And the function we use to make a Dom element is the h function. And we're just going to create a button element and we're going to put the pleasantry text inside the element. All right, so let's run the demo. There we go. We've got a button, but it doesn't do anything. And our specification says that it's supposed to respond to pleasantries, not just invite them. So we need to do a bit of work still. We're just going to add an event handler to our button it. All right, so let's run that again. There we go. There we go. Polite little component there. All we got left to do is export the component. And I'm also going to comment out this demo, but I'm not going to get rid of it because it's going to be useful the next time I come back to work on this module. So I'm going to keep it around. Now, what we end up with here is something that I like to call a whole module because this module contains its specification it contains its best and it contains its implementation. And this is actually a very powerful idea. It gives you better portability. You can pass your modules around to different projects, they don't lose anything. It gives you better maintainability. Like how often have you found your way to a source file in an unfamiliar code base and you don't know where that file's tests are, you don't know where its specification is. This is good, because when you end up at that buggy line of source code, then you've got your specification and your best right there. You can just immediately start fixing things. Another thing that's neat about using this whole module repl approach is that you get a better feedback loops. So this is what our feedback loop looks like. Now notice that the build and reload steps are gone, and instead of saving the file, we evaluate code. The test step is going to take less time because we're not running tests for anything else except this particular module. So we've just got less code to run there. Debugging is going to take less time because we're not running the whole application, we're only running our module, which means that we're not going to have to worry about bugs that exist elsewhere. So it's going to make it easier to track down our mistakes. The repl I've just been using is called replete and I wrote replete because I'd heard about people using the repl like this in other languages, but I'd never heard of someone doing it in Javascript. I wanted to know if it was possible and I wanted to know what it was like. Now I can report back. I really love it. I think it's really great having this super fast feedback. I use replete for front end code, backend code, crazy experiments, stuff I'm putting in production. And you can use it too. It's fully open source, it's on GitHub. You just have to get that source and then install a plugin. There's plugins for sublime vs code, neo vim and emacs. The plugin actually doesn't do much. All it does is listen for keyboard shortcuts and send messages to replete. So like the plugin for vs code is like 60 lines of javascript. So you could write that in an afternoon. Once you got your plugin installed, you can start evaluating your code in any browser, to any modern browser, even a browser running on your phone or something. You can evaluate code in node and you can evaluate it in Dino, which I feel is the spiritual successor to node. So just to go back to this comic, like I love XkCD, but this comic kind of depresses me because it reminds me of how I feel when I'm waiting for a test step or a build step, and I'm not having sword fights. Like, I feel restless, I feel trapped because I want to continue on with what I'm doing. I don't want to move my focus onto something else. But I can't progress until I get that feedback, and it drives me nuts. And it's a waste of time, right? So programmer time is now the most precious resource in any software project, so we just can't afford to waste it. Good news is the computers are really fast now. They can do loops of things at the same time, and if we make it a priority, we can devise feedback loops that have no noticeable delay, right? So feedback loops that feel like that brand new project, but they keep feeling like that no matter how big the project gets. And I think that's in the spirit of what John McCarthy was talking about in the we can have that now, especially with Javascript. Thanks everybody. Thanks. If you made it through that, I found these two things really cool. What makes Repl is a podcast episode that just really explains how to do repl driven development. The difference between poking around on the node repl and really getting it integrated into your text editor. The second thing is a video that goes a bit more in depth. I love talking about this stuff, so feel free to email me. I'll talk about repls all day. I've got a blog, I've got a GitHub. Have a great 42. Thanks so much everybody. See you later.
...

James Diacono

Software Engineer @ Equimaps



Awesome tech events for

Priority access to all content

Video hallway track

Community chat

Exclusive promotions and giveaways