 Okay, hi everyone. My name is Sanjay Varma. I've been writing Rust for just over two years now and I'm the author of a Rust library or crate called Turtle. The Turtle crate is unique in that it's designed to be usable by people who haven't learned programming before and it's actually a teaching tool that's for anybody who wants to teach Rust to other people today. So today I'm going to talk to you about my experience creating Turtle and tell you about the specific things that I did to make the crate as easy to use as possible. There's a lot of thought and care that went into creating Turtle and I'm really excited about sharing that with you today. I'm going to start by giving you an overview of Turtle what it is and how to use it. Then I'm going to give you a high level tour of how Turtle works and talk about some of the specific design decisions that I made to make Turtle as usable as possible and to make sure that we can grow the Turtle project as it matures. I'll talk about some of the lessons I learned as I was creating Turtle and give you some tips on how to make your own projects accessible to a wider audience. Finally, I'll finish off with some thoughts and a summary of what I've told you about. So there are a lot of resources online for learning about Rust. There are full books, online tutorials, websites, podcasts, and YouTube channels. So where does Turtle fit into all of this? Well, the vast majority of these resources, if not every single one of them, is aimed at about the level of somebody who's learned at least one programming language in the past. So while these resources give you a good introduction to Rust, not a lot of these resources give you a really good introduction to programming. So just over a year ago, Steve Klamnik, who's the author of the Rust book and the leader of the Rust documentation team, made this comment on Reddit. He said that Rust could be somebody's first programming language, but the resources and learning materials that are needed for that just don't exist yet. So I thought about that comment a lot because Rust has incredibly good error messages. It has a friendly, kind, and helpful community, and really nice features that make you productive and allow you to have a lot of fun when you're programming. My hypothesis is that Rust is going to make a really great first language for anyone wanting to get into programming. And so my goal with Turtle is to create the resources and community that we need in order to make the Rust language a language that anybody can learn. So now that you know what I'm actually out to accomplish, let's talk a bit about what Turtle actually is. The concept of the Turtle crate is actually pretty simple. You have this window, and in the middle of this window is this little triangle. And that triangle is actually a turtle. It's the turtle's shell. So this turtle is pretty special. If we enhance this image a bit, you'll see that this turtle actually has a pen attached to its tail. That's a real drawing that took me a lot of time to do, despite what it looks like. So this pen is pretty awesome because we can use it to draw pictures. If you look here, as the turtle moves, it drags its tail and the pen actually draws the path that the turtle takes. And so this is the central concept of the Turtle crate. And you can draw all kinds of amazing things just by telling the turtle where to go. All of these were drawn in Turtle, and some of them were actually contributed by people in the Rust community. You can find the source code for all of these drawings in the examples directory of the Turtle GitHub repository. The reason this is great for teaching is that the interface provided by Turtle is fairly simple without being limited in functionality. There are movement and rotation methods, methods for controlling the turtle's walking speed, methods for manipulating the pen, and even some commands for filling the shapes that you draw or controlling whether the turtle is visible or not. You get all of these different ways to draw with a very simple mental model to teach. It's just a turtle moving around the screen. So this type of teaching tool goes beyond the typical text manipulation of most introductions to programming. You can write lessons that produce really cool drawings without necessarily needing to dive into the more complicated features of Rust. The idea for this actually isn't even mine. If you look up Turtle graphics on the Internet, there's a pretty rich history of people using this to teach other people programming. In fact, one of the first incarnations of Turtle was a real physical robot. The robot would move around a piece of paper and draw pictures. A software version of Logo was created to be used with a programming language called Logo. Logo is a simple command-based language that allows you to draw pictures using a turtle. Lots of languages have built-in implementations of Turtle graphics. For example, Python has a module, a turtle module, that allows you to draw pictures just as easily as if you were using Logo. So in this code, Turtle.forward instructs the turtle to walk forward by 200 steps. By calling Turtle.right, you tell the turtle to turn to the right 90 degrees. The idea with the Turtle crate is that we can now do the same thing in Rust. Notice how both the Python version and the Rust version look almost identical. It was really important for me to make sure that this was a useful tool for teaching Rust, not just an identical copy of the Python implementation, and so the Turtle crate is written in idiomatic Rust and follows Rust best practices. One thing you'll notice in the Python code on the left is that we directly call methods on the Turtle module that we imported. We didn't create any Turtle explicitly, it's just there in the module itself. And so the Python implementation uses some global mutable state inside of the module itself in order to implement that. Global mutable state is this pattern that can lead to a lot of subtle bugs and cause problems in your code. So that's why in the Rust implementation, you actually have to create the Turtle explicitly as a local variable, and you even have to mark it with the mute keyword in order to modify it. Rust won't even let you use the forward and right methods if you don't declare your variable with mute because both forward and right modify the Turtle itself. So this is a tiny bit more friction than you had to experience with the Python implementation, but I think it's worthwhile because it teaches people good habits that'll help them in the future as they continue programming. And the wonderful thing about Rust, and this is particularly for Rust, is that even if they do, for example, forget the mute keyword, there's this really nice error message that'll tell them exactly how to fix the problem and tell them what went wrong. That means that even if you're new and you're still not used to things, it's very hard to get stuck if you just read the error message. I'm very proud of the fact that although there are a few differences, the Rust code is basically the same as the Python version. And accomplishing that took quite a bit of effort. So let's talk about how I did it. The Turtle crate has quite a bit of stuff going on behind the scenes. The crate creates a window, manages events like the close button being pressed, the window being resized, or someone clicking on the canvas, and still has to respond to all of your drawing commands with the appropriate actions. Behind the scenes, Turtle has to run a complete event loop while still allowing you to write normal looking code that is reasonably simple to understand. Well, what's an event loop? Well, basically, the idea is that both the program and the user are continuously trying to do things at the same time. A program written using only the Turtle crate might be trying to draw a picture or do some calculations, whereas the user might be minimizing or maximizing their screen, clicking on something, or pressing a key on their keyboard. An event loop simply manages all this continuously in a loop. Inside of an event loop, you take turns quickly switching back and forth between handling the events from the user and performing the internal processing of the program. This isn't actually too hard to grasp once you get the hang of it. And if I were writing a general purpose graphics crate, I would definitely allow the user of that crate to write their event loop themselves so that they could have full control over their application. But that really doesn't work the same way for Turtle. It's not that important here because we're really only trying to be a good tool for teaching rest. These kinds of details don't really help us, and that's why we hide all of that behind the simple interface that you saw before. So this is how the architecture of the first incarnation of the Turtle crate looked. When you create a turtle in your code using Turtle new, the Turtle crate spawns a new thread. That thread is where we create the window, run the event loop, and do all of the rendering and event handling that I described on the previous slide. Since all that is going on in a separate thread, the user's program is able to run normally on the main thread. When you call methods like turtle.forward or turtle.write, the main thread sends a message to the event loop thread to let it know what happened. The threads can communicate back and forth to do drawing and handling events as needed, and this is a great and relatively straightforward way to accomplish our goal of having an easy to use interface that hides all of the complicated details of the event loop and rendering. The event loop runs in the background, and the main thread goes on normally telling the Turtle what to do in each step. Now there are a couple of things to consider about this, though. Normally the program ends when the main thread ends. Now we don't want that here, because that would mean that the window would immediately close after it finished drawing whatever the user's program specified. To prevent that, when the Turtle goes out of scope, we actually wait for the window to be closed, and then we end the main thread. In addition to that, we need to make sure that any memory that's shared between these threads, any information we have about the Turtle or the drawing or anything like that, is available to both of them as much as possible. We wouldn't want the main thread to wait for the background thread or vice versa. So this approach actually worked really well, and it allowed me to get Turtle off the ground. I had a working crate, and I even published it for the world to see. However, given that the last slide was titled attempt number one, you probably already guessed that this didn't last long. Yes, unfortunately, the day after the crate got a lot of attention, someone came and found out that it didn't work on Max at all. See, I developed Turtle on Linux, which is apparently totally fine with you creating and managing application windows in any thread at all. But on Max, the implementation of window management isn't thread safe. That means that in order to manage a window, you need to create it and handle the event loop on the main thread. This is a huge deal, because the whole magic of Turtle is that you could write simple, normal looking code on the main thread without doing anything special in order to create the window. Like it would not be good to have to force somebody to squeeze an entire event loop in the middle of the Turtle code we saw before. The code on the right here is completely different from the left and way more complex for a beginner. So it was unacceptable for me to have to add this extra burden of complexity to Turtle. Turtle just couldn't be an effective teaching or learning tool if you had to learn about all of this just to write simple programs. So after a lot of thought and consideration, I came up with the second architecture. I needed some way to continue to allow the user to write their program on the main thread and also create and manage the window on the main thread as well. We can't actually do both of these together at the same time because the event loop has to be able to quickly switch back and forth between rendering the drawing and processing events. It wouldn't be good to have the user's program and the event loop compete for time. Now if only there was a way to have two main threads, that would solve all of our problems. Well it turns out there is actually a way to do this. While you can't have two main threads in one process, you can have two processes with one main thread each. And so the solution I came up with to give me everything that I wanted was to spawn a new process to run the event loop instead of relying on a separate thread. Now processes are a little bit more complicated to handle than threads, but if you do it correctly, it turns out to not be that bad. We're still sending drawing command messages, it's just that now we're doing it between processes instead of between threads, and we're still waiting for the window to be closed before we exit main thread number one. Instead of sharing state between threads like we were before, we now have to deal with synchronizing that state between two processes. The way we handle this today in Turtle is pretty simple. We just keep all of the state in one of the processes and then we make the other process request it whenever it wants to look at it. So this attempt actually ended up working great. It took me about two weeks and 59 commits to convert the old architecture to the new one, but that's mostly just because I was busy during those two weeks and I'm not afraid of commitment. In reality, it probably only took about a day or two of work to convert the old thread-based architecture to the new process-based one, and this has actually been so successful so far that this is still how Turtle works today. Now one of the greatest things about this is that it actually didn't require any changes to the public API at all. The entire Turtle crate stayed the same, but the internals of how it worked got completely switched out. The Turtle crate you see online today is in no way complete. It's fairly stable now, but there are still a ton of features that we could potentially add. I've taken a lot of time to carefully plan things so that we can reach a minimal viable product and then build all kinds of really cool features on top of it. Turtle has a really well-organized issue tracker with lots of good first issues and help wanted issues if you're looking to get involved. We're really open to anybody of any experience level with programming or with Rust and we'll help you figure things out as long as you're willing to work with us to do so. We especially love it when people come and contribute examples to Turtle and there's this great example idea label on GitHub if you're looking for inspiration. We really want to see it if you use Turtle to create something cool and these example ideas are just there to spark your imagination. If you're interested in contributing to Turtle, but you're not sure how to get started, we have a detailed contributing guide that walks you through the process of contributing step by step. A great way to contribute if you're looking for something to do is to read this contributing guide and tell me where you get stuck so I can fix it. Opening issues is fantastic. The future of Turtle has a lot of really cool features. I want to add things like multiple turtles, 3D drawing, text rendering support. We want more widgets like buttons and text fields for user input. We even want to add asynchronous turtles using async, await, and the futures create. And add web assembly support so that you can write Turtle code from your browser without downloading anything at all. These are all really exciting ideas and I'm definitely going to need all of your help in order to accomplish them. In particular, I need people to go and try Turtle out and see what you run into. If something in the API needs work, it's better to know now before we commit to a stable release. Trying out the crate today and drawing something non-trivial is a great way to help out today. As I was designing Turtle, I put a lot of thought into what kinds of things the crate needs in order to be accessible to people who don't know programming at all. I don't know of any other crates that try to do this, so it was particularly important that I think about it a lot and get it right. I'm now going to share with you some of the things I learned along the way and give you some tips to help make your own crates more accessible to a wider audience. So it's true that not every crate is aiming for as large of a group as I am. Most crates probably don't need to or even shouldn't try to cater to people who don't know programming. It would be way too much to ask of every crate author to teach basic programming to every user of their crate. That being said, the nice thing about at least thinking about it is that you have the opportunity to increase the number of people who can use your crate successfully. I've sat down and taught rest to people who don't know programming that well and managed to explain some pretty complicated crates. Sometimes you just need somebody to put in the time to write something that will teach you what you need to learn. When you put in some effort to make your crate accessible to an audience that might not be familiar with what your crate does, it benefits everyone, including the people who are experts in it like you. I'll give you a small example of something that I did to make Turtle accessible that actually ends up helping me a lot. Turtle isn't just meant to be a good teaching tool, it's meant to be a very accessible project for people who want to contribute to a Rust project. That's why if there are any quirks that might trip someone up when they're trying to contribute to Turtle, I take extra care to make sure that people get the information they need. In most crates, you can go in and run cargo tests to run the tests for that crate. But since Turtle has a graphical user interface, just running cargo tests alone would make a whole bunch of windows pop up unnecessarily. This is undesirable, and closing all of these windows is really hard. So I added a special test feature to the crate that disables any window creation during tests. The problem is that you can't just run the regular test command anymore, you have to run cargo test with the features flag and then add the word test. I didn't want people to get tripped up on this, so I used a special macro that Rust recently added called the compile error macro, and so with these two lines of code, if anybody tries to compile tests without the appropriate features flag, they get this really nice error message that tells them exactly what to do. This was supposed to be a small quality of life improvement that I only really intended to help new programmers, but it's something that's helped me a whole bunch of times as well. There have been plenty of moments where out of habit, I've run cargo test, and instead of getting a whole bunch of windows popping up and having to close all of them manually, I've gotten this nice error message that reminds me what to do. Thinking about less experienced people using your code can really help you as well. So some of the things I talk about today are probably going to seem a little bit obvious at first. This first one, good documentation is probably something you know to do already, right? Like want to make your crate more easier to use? Write some docs so that people know how to do it. The thing is, to make your documentation actually good, you need to put some thought into it. I find personally that the first time I write documentation, I only really end up writing it for myself. There are some docs, but really I'm just writing notes to myself so that I don't forget a couple of things that I want to remember. To write documentation for a wider audience, you need to actually think about the people who are going to be using your documentation. You need to think about what they know, what they don't know, and what you're going to need to explain to them in order to make your documentation as useful as possible. You don't want to bog them down with information, and you want to structure your docs so that they get the most important information first. It's also a really bad idea to try and write your documentation after having written all of your code, because you'll probably forget most of the important things that you want to write down by the time you get to your documentation. In the turtle crate, we take documentation really seriously. We aren't perfect yet, but we really make an effort to have detailed documentation that covers the information you need in order to use the item being documented. One example of a method that has some pretty good documentation is the set speed method. Here, we take the time to explain the most important information about the method, what it does, how to call it, when it might panic, and we talk about how to achieve specific effects using the method, using some special values that it can take. Since turtle is targeting new people who aren't familiar with programming and aren't familiar with Rust, we also take the time to explain some Rust concepts that the user might not be familiar with. Now, one way you can avoid such long-winded explanations is by linking to the many Rust resources that are available online. We do that a lot in the turtle documentation, and if you're a little apprehensive about writing docs yourself, this is a great way to cut down on the total number of things that you need to write. So don't hesitate to take advantage of the resources that other people have created to make your life easier. One of the final things that I'll point out about writing good documentation is that you need to think about how people will find the information that they need. The users of your crate will not always be experts in it, so they need to know which types, functions, or methods they should look at if they're trying to accomplish a certain task. One way you can help them is by putting something at the root of your documentation that directs them to the places they might want to go. You'll find that this is convenient for yourself as well, because you can reach the documentation that you want to see faster. Examples. Examples are really important, and it's really easy to write bad examples. There are quite a few methods in the turtle crate that need to have their documentation improved a lot. In fact, sometimes in my own haste to finish something, I've written examples like this. This example is more of a unit test than a real example. It doesn't explain anything. For an example to be useful, you actually need to motivate it and talk about why people should use it and in what situations it comes in handy. If you find this really difficult to describe for a particular item, you should really think about why it's in your public API in the first place if you can't even explain what it's supposed to be used for. A method with much better documentation is the set pen size method. Not only does it have a complete example that motivates the use for that method, it also gives you a picture of exactly what result is produced by running that example. Now, you may not be able to put pictures in your documentation, but you should strive to at least provide examples that show why an item should be used and then show what happens as a result of that item being used. Examples for individual methods are meant to show how a specific method is to be used, but what about complete examples that take advantage of more of your crate? Well, Rust has great tooling that allows you to create these kinds of examples easily. Cargo can run any Rust file placed in the examples directory of your project and you can use these to provide more comprehensive examples of the major use cases of your crate. Turtle has a lot of examples in its examples directory and we're always looking for more people to add examples of the things they've drawn. So far, we've talked about good documentation and examples, but our discussion wouldn't be complete if we didn't also touch on writing a guide. A guide is a tutorial that goes through the key pieces of functionality in your crate. Your guide needs to at minimum walk people through the first time using your crate. Now, once you've done that, you should aim to show them detailed examples of each of the major features and use cases for your crate. The difference between a guide and the examples in your examples directory is that in a guide, you're able to explain your crate and how it works in detail. This is essential for somebody to have a complete understanding of how to use your code, and a guide is actually one of the major pieces that Turtle is still missing. I want the Turtle guide to be an introduction to programming that incrementally teaches people programming in Rust by having them draw pictures. The final thing that I want to mention is that is the Rust API guidelines. These guidelines go through a lot of the different aspects of creating a Rust crate and tell you exactly how your crate should work in each category. There's a checklist that you can use to make sure that your code is idiomatic and follows Rust best practices. I highly recommend these guidelines for making sure you're writing the best Rust code possible. So thank you for listening to my talk. We covered a lot today including how the Turtle crate works and how you can make your crate successful to a wider audience. Please come and try Turtle out. We really need people to try and draw non-trivial things in Turtle so that we can see what breaks. If you'd like to come contribute, we have plenty of things to work on regardless of your skill level. I also want to take a moment and thank all of the wonderful people who have contributed to Turtle already. Many people come in and they've picked up the slack when I haven't been able to work on Turtle very much, and I really appreciate everybody who contributes code and everybody who files issues. The Turtle crate has a Twitter account so if you blog about Turtle or draw something and post it, I'll retweet you if you tag this account. You can also follow me on Twitter as well. I'll be around today and online if you have any questions. That's my time. Thank you very much.