nbdev live coding

In this live‑coding session, Hamel Husain (moderated by Ali) introduces the fast.ai ecosystem and then demonstrates how to create, document, test, and publish a Python library entirely within Jupyter notebooks using nbdev. He starts by creating a GitHub repository from the fastai‑nbdev‑template, configures the settings.ini file, and writes code (a Card class and a Deck class) in notebooks, using nbdev export flags to generate .py modules. He adds inline documentation and assert‑based tests, builds the library with `nbdev buildlib`, generates documentation with `nbdev builddocs`, and serves it locally. He then pushes the repo, enables GitHub Pages, sets up continuous integration to run the tests, and finally publishes the package to PyPI. Throughout, Hamel answers audience questions about syncing code between VS Code and notebooks, the impact of nbdev on PyPI quality, production use of nbdev‑generated code, and broader career advice. The talk emphasizes how nbdev unifies code, tests, and docs, reduces boilerplate, encourages better software engineering practices for data scientists, and showcases the future trend of integrating software engineering into data‑science workflows.
Chapters
It is my pleasure to introduce Hamel Husain this evening. Hamel and I recently reconnected after, I want to say, years, if not over a decade. And when we reconnected a couple of months ago, I wanted to gauge his interest and asked him whether he would be interested in doing this event with us. And the very first thing Hamel says is, "Ali, I'm actually turning down opportunities to speak just to manage my bandwidth." but for a friend, I will do it. And I'm thinking, wait, we're still friends? But that just shows you the type of person Hamel is. We picked up right where we left off. He's genuine, sincere, and above all, humble in his approach. So we're very excited and thankful that Hamel is able to join us this evening. We both actually were at SMU doing our undergraduate degree, but his trajectory was much steeper than mine. He went to pursue a law degree at University of Michigan. And then wanted to get deeper into mathematics and sciences and so pursued a master's in data science. From there, he went to work on amazing companies such as DataRobot and Airbnb. Currently, he's at GitHub. His primary focus is to work on open source platforms and projects such as Machine Learning Ops, MLOps, as well as fastai and fastpages. Please help me welcome Hamel Husain.
Thanks a lot, Ali. That was really humbling introduction. Before I get into my presentation, it sounds like a lot of people don't know what fast.ai is. That is worth talking about because that is the organization that produced this platform that I'm going to talk about today. The way you can find about fast.ai is go to fast.ai. And you can see that it's a site that has a blog on it, but also has a lot of links. And what I would say, it's the most wonderful course on machine learning, specifically deep learning. Before fast.ai, deep learning was kind of a very hard thing to learn how to do successfully. fast.ai was one of the first MOOCs to teach that from a top-down fashion. In a way that was very accessible. Not only is it a MOOC, but it's also a library built on top of PyTorch. We can see it on GitHub, fastai. Let me just go to fastai and let me make this a little bit bigger. Fastai, they have a lot of different projects. We're going to be talking about MBdev today. But there's also, of course, fastai itself, which is the deep learning library. You could think of it as a high-level abstraction on top of PyTorch, but it has a lot of interesting state-of-the-art things in it. So just because it's high-level abstraction doesn't mean that you're kind of eschewing state-of-the-art stuff. In fact, a lot of fastai things have beat a lot of benchmarks, including academic benchmarks. So it's actually very interesting. Lately, fastai has been getting a lot more into software engineering. So projects like nbdev, which we're going to talk about today, but there's also fastcore, which is a very interesting Python library that adds a lot of neat things to Python, and I really— I suggest that you check it out, um, you know, after this presentation. It's actually really fascinating. So, so that kind of is a good background for what I want to talk about next, which is, um, why I'm doing the presentation I'm doing today. So whenever I do a presentation, I try to kind convey something unique that I think that folks may not be aware of or may not see. So the last thing I wanna do is present on how to classify cats and dogs with machine learning because there's tons of videos out there like that and there's no reason why you should watch me for 45 minutes talk about that. So instead I wanna talk about something unique and what I wanna talk about is new ways of writing software. Now writing software is actually really important for data science. The, you know, as you know, data, when you build a model or really do anything, if it's going to touch a system of any kind or a product of any kind in a company, it's going to have to be integrated with some software. And there's a lot of concerns around that you have to deal with as data scientists. Such as how to build a data pipeline, how to serve a model, how to kind of write your software and package that in a way that other engineers can understand. You're usually working with other engineers. And so software engineering is really central. And so anything in your toolbox that can allow you to be more effective at writing software is gonna make you a much better data scientist. And so that's why I think nbdev is really neat. So what I'm going to talk about today is a new way of writing software. Now you might be thinking, why do you need a new way of writing software? People have been writing software for decades. Why all of a sudden do you like think they might need a new way of writing software? And I understand that kind of skepticism, but that's why I think it's exciting, because when you see it, I think it'll click. I don't wanna talk too much about it in theory, I just wanna jump in and show you what it is that I'm talking about. And it's actually using a lot of familiar things, so it's not like a very foreign set of tools, but when you see it, I think it will be exciting. Okay, so what I'm gonna do today is I'm gonna create a software package, but I'm gonna write it with nbdev. This is the repo, nbdev. Just to ground everything, everything I'm going to be talking about today, if you go to the repo, you'll see the link to the docs. Let me just make this screen bigger because I know that I'm sharing my screen. If you go to the nbdev repo, you'll see a link right here. If you go to that link, you'll see a lot of different documentation, see an overview. With all the features of nbdev, which we will discuss. There's a tutorial. There's also this minimal example, and I'm going to be going through this minimal example. So at any point you get lost, or afterwards in the presentation you want to kind of revisit what I did in a written form, you can go to this minimal example. I wrote this minimal example, so I'm very familiar with it. And yeah, I'll be going through that and adding more commentary that might not be here. I just also wanna say that anytime anyone is confused by what I'm doing, 'cause I'm gonna be writing code, there's no slides, I'm gonna be writing code in real life, so I'll ask two things. One, be patient with me 'cause I will make a mistake somewhere, but I wanted this to be realistic. I want you to see the real process of a real engineer trying to do this in real life and not have it be some kind of, you know, show that you watch. And then secondly, if I do anything, yeah, please make sure you ask a question. The moderators will be monitoring the chat and then they will kind of interrupt me and ask that question. And I want to be interrupted, so don't be shy. Okay, so we'll jump right into it. So what I'm gonna be doing today is I'm gonna be I'm gonna take some code from Alan Downey's Think Python. So Think Python is a really excellent book if you're learning Python. The reason I like it, it's very simple, it's easy to understand, and it's written by a really great educator, Alan. And he actually writes a lot of different books on Python statistics you may be familiar with. I'm gonna take some code in there, I'm gonna kind of repackage it to nbdev. I'm gonna pretend like I'm writing the code from scratch. And what that process looks like. Let's get started. To get started with nbdev, what do you do? First, what you want to do, let me make this screen a little bit bigger. If my screen is not big enough anytime, please interrupt me because that's something that I mess up. Often. So let's go to— you want to— so the first thing you want to do is go to this nbdev template repo, which is fastai-nbdev-template. And hold on a second, let me just resize my browser here. Okay, so what you want to do is you want to click on this, and we're going to name it something. So you want to name your repository the same name that you want to name your Python package as. So, I'm gonna try to pick something that's not on PyPI. Let's just call it— I'll just call it Northwestern cars demo. And I'll just put a little description there. I'll make it a public repository so you can all see it. That's not really necessary to check that box. You can if you want. It's not going to really harm anything. Okay. So, I'm going to create this repo from that template. So, you see I'm creating this. It's going to create this repo for me, and this just kind of seeds it with all the files I need to get started within this development environment. Okay, so the first thing we wanna do is I wanna clone this repo. So, right here I have my terminal window. Let me just make that a little bit bigger. So, I really like to use this tool called gh. I don't know if anybody's familiar with it. I think it's really great, and I'll show you how that works. So, I'm gonna say gh repo clone, the name of the repo, Arts demo, okay? And then what that does is it clones the repo, and I'm gonna just go into that directory, okay? So I cloned it locally, and the first thing I want to do is I'm gonna go into a settings file here. So let me make that a little bit bigger because I know that's kind of small. Hopefully that's big enough. If it's not, stop me. I'm going to go through this and change it a little bit. Library name, I'm going to call it nwucards-dev. I'm just going to name it exactly the same as my repository just to keep things a little bit simpler for me. I'm going to say user is my GitHub username. Then I want to fill these out right here. I'm going to take these, okay, description. Let's see, a demo of nbdev. Then keywords is, I'll just put nbdev. Then I'll put my name, Hamel Husain. Then I put an email, that's a fake email. And I'll just put copyright. I'll just make this up for fun. There's no such entity that is named that, to my knowledge. There we go. I'll uncomment those.
Hey Hamel, we have a question coming in. Is this a Git code that you're writing right now?
No, this is actually a file called settings.ini that's in the GitHub repository. So that was created when you created this repository. It was automatically dropped into the repository for you. So this is just a text file, and I'm just editing it, putting— I'm setting it up. The reason I'm doing this is when you set up a Python project, usually you have to go in, you have to create a, create a bunch of different files everywhere, uh, and that has a lot of repetitive information. And so what we're doing is we're just putting this information in one place And nbdev is going to propagate things like the description, the username, whatever, to various concerns that you have. And I'll show you how this works. But basically, it's like a way to avoid boilerplate. Even though this looks like it might be boilerplate, it's not because you never have to repeat this again. You don't have to put your username in several places. And when it gets uploaded to PyPI, when you want to publish your package, then it's all set up for you. Hopefully that makes sense. Let's see, I think that's everything here. Let's go right into it. We have the settings file. Now the next thing you want to do is open a Jupyter Notebook. Let me actually go into this repository. I'm going to just open a Jupyter Notebook. Let me bring that over here and let me make it a little bit bigger so you can see, minimize this window. You get these notebooks that are automatically in your repo, core and index. I'll talk about these one step at a time. What we want to do is I want to go to Alan Downey's repo. Let me go to his repo. Alan Downey. Let's see. What I'm going to do is I'm going to pretend like I want to implement this code. He has some code here, something that implements this card object, which is easy to understand. It's basically a card in a deck of cards. What you might get in a playing card deck. And I'll show— and so we can go through this. So I'm just gonna copy and paste this code. Oops, my copy and paste is not— let me just, let me just make this a size that I'm gonna go to the raw mode so I can copy this. Okay, we go. Then what I'm going to do here is, I'm going to go ahead and copy this code and I'm going to explain everything that's going on. So nbdev works with flags and what happens is you write your code in notebooks and it gets exported automatically to Python code. So I'm going to show you how that works. So first of all, let's name this notebook, let's start filling it out. So I'm going to call this card. And this 00 doesn't have to be there. It's just a convention that I use, that nbdev uses optionally to sort the files in the file system. I'm going to create a couple of different notebooks and I want them to be sorted for me by filename. So that's what that means. So we're going to say, okay, let's— and this first cell right here, Tells you what Python module we're going to export to. We want to export to card.py. I'm going to change this to card. I'm going to change this to card here. This is going to make sense once I generate the code. I'm going to say, okay, and let's just make this a little bit more informative. I'm going to say this is a playing card. This is some boilerplate here. This is really helpful just to leave it. This is a part of nbdev. And it has some helper functions in it that are necessary. So, we'll just leave it for right now. So, when you're writing code in nbdev, what you wanna do is, you know, you wanna write your code per usual, but, so let's just go through that. So, this is a playing card, and what you wanna do in nbdev is you wanna write your documentation and your tests in the notebook itself. Let's go ahead and do that. Let's use this code and let's document this code. How are we going to document this code? Let's write something about it. Card. What is this? Card is a class that represents single card in a deck of cards. For example, and let's see, okay, let's, let's demonstrate how this thing works. So if I do card and then let's see, it has a suite or suit, sorry. So see, suit is, let's pick one, let's say 1 and rank is 3. Let's see what happens. So, it gives you that. Actually, let's— let me actually add something here to make it print nicely. Otherwise, it kind of may not. See if that helps. No, self, I do self here. There we go. So, you see, okay, that's gonna give me a 3 of diamonds. And now we might want to have some tests. So, we say, okay, let's create a card. So, let's just do another one. And okay, so that's what we just did right now, but we wanna test it. So when you write code, it's helpful to write tests and we can just write the test right in the cell. So assert, you know, that this thing actually equals this. Now usually you would wanna like think about it more and make sure like this is actually right, but I know that this is right. If you look at it a little bit, you'll realize like, yes, this is supposed to be a 3 of diamonds. Then let's create, this is just for posterity, let's just create one more test. Actually don't know offhand what that one is gonna be. Oops, what did I do? Actually we want a different one. Oh, this is supposed to be that. There we go. Yeah, so that's, huh? Oh wait, I was doing the wrong printing, the wrong thing. There we go, Jack of Hearts. So yeah, okay, Jack of Hearts, does that seem right? Let's see, rank is 11. So that seems right, and then hearts. Is the 0, 1, 2 index. So yeah, that makes sense. So that, that is right. Okay, so let's just put a pop of test in there like that. Oops, it's my copy and paste doesn't want to cooperate with me. There you go. Okay, um, oh, we want to assert, of course, I want to assert that. All right, and then let's, let's, uh, Let's kind of document some of the other functionality that's present here too. Like, you have— so what we have here is you see that Alan is actually adding these dunder methods that are allowing for these comparison operators. So this, for example, this less than, um, or this dunder lt allows you to compare cars to each other. So for example, um, You know, let's see. So, let's see. So, the Jack of Hearts should be bigger than the 3 of Diamonds in terms of, you know, rank. So, let's just check that that actually is true. So, yeah, it is true. I wanna assert that. But let's also, it's also important to say that. So, say you can do comparisons of cards. 2. Okay, now there's other ways to use— there's fancier ways to do tests with nbdev, but I'm just showing you the basic functionality so you can get the idea.
Okay, we have a question coming from the audience. Um, into top Hamel row card, which will be card .py, is the test also exported to the same Python module?
I'm going to go in. That's a great question. I'm going to talk about that right now. Right on time. This is how it works. You have your test, you have your code. Now, if you go to the original code, let's just take a moment to reflect what the original code looks like. So, when Alan wrote his code, he wrote card and card.py. He wrote some code. It does have docstrings. So, he wrote code in one place. Then, if you look at his library— oh, let's go back here. You see that he has tests in a separate file. So, he has this unit test and then he He actually adds some tests here. It's in a completely separate file. It's not actually clear what the intent of this test is. It's not super clear what he was trying to test or convey in this test. And again, it's in a completely separate file. And the documentation for this code is yet in another file. So the documentation for this code is in this book is in this other format, in this book folder, sorry. This book folder contains HTML and so on and so forth that has a documentation for that code. So what we're seeing here is most people don't write tests and they don't write documentation.
Why?
Because it's so painful. Because as you see here, this is the way it's typically done in a Python project. You have code in one place, you have tests in another place, You have documentation in another place. It's no surprise that most people don't write tests and most people don't write documentation, or they don't do a good job of those. And nbdev, what it's really exposing is something called literate programming, where you write code naturally as the way you would want to see it as a human being and kind of have a conversation about your code. That's how it works generally. That's why we're doing this. Now, how does all this become code and what is the point of doing this? That's what I'm going to show you in a second. Let me first go to open this notebook. This is a notebook that generates the README. We haven't created a library yet. I'm going to comment this out so it doesn't cause any problems. But the next step I'm going to do is really important. I'm going to go ahead and sync this notebook with code. I'm going to open my terminal here. Let me just zoom in. I'm going to use this command nbdev buildlib. When I install nbdev, these command line tools become available to me. When I do that, you will see I go into this project now. You will see this folder has been created and now we have— oops, I guess it's— oh, you know why it's not here? One key thing is you might not want to— this code right here is not actually code you want to put in your module. But this code is, this is tests and this is kind of like for documentation. Some of it is test, some of it is documentation. So what you want to do is you want to put this flag here called export. And so export, what that does is it says export this to an external module. In this case, this default export, that just is a short, hand things so I don't have to repeat export card in every cell, if that makes sense. So let's do it again, nbdev build dev. Okay, and boom, it appears in card.py, it syncs. And you can also change something here and it syncs back to the notebook, but I won't go into all those details again, I'm trying to keep it simple for you. Okay, and then I want to show you the next thing. So I'm going to show you the docs. You can do nbdev build-docs, and that's going to generate the docs. Now, all of this happens automatically, but I'm showing you one step at a time so that you can see everything. If you use this command make doc serve, you can actually serve the documents so you can preview them locally. Let me bring it, it's in another browser here. So you can see, okay, this documentation has been created. This is the README, which doesn't really have anything in it yet because I haven't filled it out, but this is the minimal thing that we just created. This is documentation. You can see, um, so you— table of contents is automatically created. You have this class has been created, uh, you have some documentation there. It links back to the source code automatically. Oh, well, I haven't launched this yet. I haven't put this in GitHub. This is just running locally, so this link doesn't actually exist yet. You can see this is documentation, and this documentation is generated automatically from the notebook. It all comes for free. Let me just see what I want to do. Let me think about what I want to do next here. Let me think about this. You might be wondering, the card, only the init of the card is showing. But what if I want to document some of these methods? There's something called show_doc. Let me just— I'm going to do show doc and I'm going to say I want to do card LT here. What that does is it's going to show the method of the card. I can actually move this here so that way you can show documentation, same header as you would here, If I regenerate the docs, you'll see what this means. Let me just— what's the name of this repository? NW something. It's making the docs again. Let's see. Oops, it keeps opening in a different window. Let's just bring it back here. And then you'll see that, you can see that that heading has been created. So that's how you can do it. There's a lot of different ways you can do this. You can actually, there's a way to define these methods separately in a separate cell from, you can actually break it up. That's a little bit more advanced, but we don't talk about that, but it's in the documentation for anyone that's interested. Let's keep going. This is going to get more exciting in a moment. Now let's go ahead and push everything we have to GitHub. When you first install nbdev, let me actually make this bigger because you probably can't see my terminal and probably can't see any of these commands. You usually have to install git hooks. Which I didn't do, so I'm just gonna— so I'm doing this live and make sure that— so what Git Hooks does is it helps you do some of the stuff automatically so you don't have to fumble around with so many commands all the time. Um, so let me see, so let me see all the files that changed. So we see, okay, we have all these files that were created. Um, a lot of these were created by mbdev, you see. So So these are documentation files. These are files that were kind of in the template. So let's just add— I'm just going to commit all of them because I do want all these files. Let's try to do a better commit message. That's not a great one either, but that's okay. Now we're getting started. Let's see what's going to happen. You can see I just pushed this. Now part of getting your nbdev repository setup is to enable GitHub Pages. GitHub Pages, what you do is you go to your Settings tab, scroll down, What you want to do is you want to select master, you want to select docs. Good. Hopefully what this will allow to happen is now your docs can be served from this site. It will take some time for it to register. But while that's happening, I want to show you something else. So there's something called continuous integration. So when you have tests, those assert statements, you might be wondering, how do those get run? Where do those get run? And the answer is they get run inside this continuous integration system that happens for you automatically. Now, a lot of continuous integration can be somewhat of an advanced concept, but the idea is every time you make a change to your code, those tests should run. That way you know if you broke anything. And nbdev does that for you automatically. So on GitHub, you know, you'll have— it'll run this test and it'll— it, um, in this case all tests are passing. Now if we were— if we change something to fail the test, so let's try that. Let's actually fail a test. Uh, let me see where the— I'll just— I just need to make this smaller. Fail the test. Okay, let's see. So, let's actually assert c is greater than c2. That should fail. This is the worst error message ever. Just humor me in that and just assume that for some reason You didn't know. Okay, so let me just do this again. So let me— okay, so I have this notebook. I'm going to add it. So this is the card. Hey, when that happens, we should see something break. But, and I'll show you what that means in a moment. So let's head back over to this and let's see what happened with the GitHub Pages, why don't we? And let's see if we have that site. There's too many things in the way. Here we go, settings. Okay, let's go to GitHub Pages. Oh, it doesn't seem like it's quite there yet. What's going on? Ready to be published. What was that all about? Oh, that's because I just changed it. Okay, of course. So it says that when you change something, it takes time to rebuild. So yeah, it's right there. So let me open this in another tab. So there we go, this live. So you have your own web page with documentation about your software hosted for you You don't have to know anything about web development, you don't have to know how to host a webpage, you don't have to know anything really except how to use nbdev and all this gets created. You have your own live public site that you can use, your documentation site. You don't have to know all this stuff to make it happen and you don't have to know anything about HTML, CSS, JavaScript, anything. It just gets created for you. Let's go back and check. Let's go find out if that test broke. Hopefully it did. We see that it did. You get this red X and you'll get a notification in your email by default if something like this breaks. Let's go ahead and see it. You see when you run the test, we got this assertion error that something is wrong. This is a way that, again, is the best practice way of you know, having things run. Now, we just wrote code very naturally. Like, we just put it in a notebook and had a conversation about it and wrote documentation in a very natural way and wrote tests in a very natural way. And you've now created something that is fairly advanced pretty fast. I'm gonna go ahead and delete this test. And let's Let's continue on. Okay, so let me think about what I want to do next. Okay, so let's, let's add a little more code to this for a moment. So I'm going to create another. So let's go to Alan Downey's code, that card. And I'm going to actually take one of his this deck thing, and I'm going to put that in another Python notebook, just so, or another Jupyter notebook, just so I can show you how it works to create different files. So, I'm gonna create a new one, I'm gonna call it deck. So, 00-deck, okay, default, x, I think that's right, and call it deck. And I'll just paste this code here, okay, and let's actually do the same thing. Let's try to document this code. So, something similar, so I'll just write something real quick. Deck of cards is a collection of card objects. I copied and pasted that from somewhere just because I have a feeling you don't want to spend a lot of time watching me type. And let's kind of look at how this works. So, what's something interesting? So, a deck of cards is a collection of card objects. We see that there's a remove card thing here. That's kind of interesting. There's also a pop card that pops a card off the deck and gives you— and returns a card. Pretty interesting. So, how does that even work? So, let's check it out. Deck equals deck and deck.pop card. Oh, we need to import card. That's, yeah, we need to do that. So, from, oops, from, what is this called again? Nwudemo cards. Card, import card. So notice how the library is available to me within the notebook. That's really interesting. NumpyDev taking care of a lot of things behind the scenes so that I can import the module I created previously, and that's very handy. Okay, so let's pop the card. King of spades. Okay, so we're getting a card. I want to actually, is this really a card or is this some kind of, so let's see. What we can do is I want to know is instance card. Yeah, that's right. Let's put an assert on it. There we go. That's a great test to put right there. What about this remove card? That looks interesting. Let's document that. Let's do a show doc. Deck.remove_card. Oh, we want the uppercase deck. Show_doc is not defined. Yeah, okay. I'm just gonna do that. Okay, so let's see. Okay, so removes the card from the deck and raises an exception if it's not there. Okay, fine, fair enough. So, let's create a card. So, let's see, I'm gonna say, first of all, how do you even remove a card? What do you pass into remove card? You pass in a card. Okay, interesting. So, I'm gonna create a card. Let's see, card. Let's try that, 3 of hearts, okay. And I'm gonna say, I have a deck, I'm gonna remove card, I'm gonna remove that card. Fine. Now, how do I know that it's really removed? Hmm. Well, it looks like this deck of cards has a cards attribute. So, actually, maybe I should, maybe just for clarity, I'm gonna create a deck just fresh, just to make sure that everyone's following. And I think, yeah, it looks like, okay, you got all the cards here. So, hopefully when I remove the card, it's not there anymore. So, I should be able to say, c is not in the deck of cards, hopefully. Oh wait, what am I doing wrong here? Not in. C, oh, not in, sorry. C is not, so C not in that, yeah, so that makes sense, so that's good. So, it's not there, but okay, well what about another card? Let's call it, I don't know, let's try another card, call it C2, and is C not in, C2 not in the deck of cards? False. Okay, great. So this card, we never removed it and it's still in the deck of cards. So I mean, it should— this should, should be false. So, um, so okay, let's do an assert. Let's do an assert here. Those are our tests. And let's write some— you never want to write a test without any words. So, um, Let's, okay, let's do, let's write something on this first one. So, I wanna say something like this. If, okay, if we remove a card from the deck, so let's, here, I already wrote it so you don't have to repeat again. I'm just gonna say, we remove the card from the deck, we can verify it no longer exists. I'll add some verbiage here, okay. There you go. Boom. There you go. Let's see, we have to make sure we export this stuff. You might be wondering, what if you want to export something but you don't want it to show in the documentation? For example, you have some helper function, that you define and you want it to appear in the library, what you can do is you can export it, but you can also hide it. And that's important to know. That's used all the time in MBDL. Okay, so let's— I saved it, save this deck thing. Okay, let me think about what I want to do next.
Um, hey Hamel, we have roughly about 10 minutes, 10, 15 minutes left.
Okay, great. Okay, I'll wrap it up soon. Um, okay, I'm gonna build the library, I'm gonna build the docs. Okay, let's see. So this is the local version. Um, okay. Oh, I didn't put a title on that. So then that deck thing, let me put a title. That's, that's good to know. So deck, and I'm gonna be creative here. Okay, I'm gonna build the docs again just to refresh that. And there are systems that do this automatically. There's things that we have that sync the notebook automatically so you don't have to call nbdev build docs. If you don't want to, you can just sync it, but I'm just doing that just because this is a demo. We'll see hopefully appear here. You see that there's this deck and look like this has now been created. This docs again has been created. Let's push it to GitHub. So let me just see what all kinds of stuff is there. Okay, I think we want all of this. So I'm just going to push it all. Okay. And the next thing I want to do is I want to actually make this into a Python package. You can get an idea what the settings.ini was all about. There's actually a Makefile here. If you're not familiar with Makefiles, it's not a big deal. But this is what allows a lot of shortcuts to happen. What I'm going to do is I'm actually going to just only do the PyPI. And that uploads it as a package to PyPI so you can pip install this, and I'll show you what that means in a second. Okay, so now this is on GitHub. Let's see if it looks like the tests were passing. Well, as of a minute ago anyways. Let's check PyPI. Let's see, PyPI, nbdev, or what did I call it, nwu, cards, something like that. There we go, look at this. So that's great. I didn't do the README, so that's not good. Let's just call it— let's just finish this off real quick. nwdemo. Let me just copy and paste, I'm not good at remembering this stuff. Okay, and then you want to do pip install this. Thanks for watching my demo. Usually you would wanna maybe, you know, you wanna uncomment this and write something about your library. So like, you know, NWU cards demo import deck maybe. Import it back, I don't know. And you know, you just want to write something in the README, maybe like deck whatever. Oh, what's a good one that I don't have to create a card? Pop card, that's what I was looking for. Let's do that. Let me actually refresh the docs too. Let me actually cheat and just push with the same commit message. Okay, and what you have here is you'll see the, you'll see the README has changed. The docs will change, the docs locally will have changed anyway. So we'll see that, okay, the docs locally have changed, the docs that, that are hosted will change too. And you would have to re-upload this to PyPI. So just to let you know what's going on. You can bump this version here, for example, but there's utilities that will bump it for you. I just don't want to introduce too much magic. Okay. There we go. And there you go. See, so you got, you got that. Now you can pip install this library and you can do all kinds of cool stuff. You can do exactly this. So there you go. That's nbdev. So in just a short amount of time, we've created a Python library that is hosted on PyPI that you can pip install for everybody to use. It also has documentation. So actually, let's go to the GitHub repository. So it has documentation, it has tests, unit tests are running automatically inside a continuous integration system. What I usually do is I take the doc— documents here, I take the link here, I just put it in the repo. Usually just add the link itself, maybe like right here in this about section. I'll put it on right here so people can find the link. But you'll see if you go to the link, this is great stuff, you know, it's already available for people to browse through and it's a real website. So most developers don't do all of this, and what we found in fastai is the entire fastai universe has been developed mostly in nbdev. So fastai, if you're thinking this is kind of crazy, like, do real people use this? The entire fastai library is built with nbdev, with the system. Fastcore is built with the system, fastpages, all of these. You can see these repositories have tons of stars, used by lots of people. They're being used everywhere. They're actually built with, behind the scenes, with nbdev. A lot of people don't know about nbdev. It's kind of like the thing behind the scenes that's being used to write a lot, all this software. A lot of people don't know about it, and that's why I wanted to introduce you to it today.
Thank you. Oh, first one is about code change. If you're doing code change in the VS Code, does it sync into notebook? I will take a pause to let you answer that.
Yeah, if you make a change in a notebook, there's a command called nbdev lib sync, and that will sync it back the other way into the notebook. There's some limitations on that. You can change an existing function or method in, in the VS Code and it will sync back, but if you write something new, that's where it gets tricky. You usually want to do that in the notebook. But I use that all the time.
Thank you.
Make quick changes.
Another question is, do you have concerns about PyPI becoming clustered with lots of poorly constructed libraries from beginner-level programmers because it seems like everybody can post it there?
Yeah, I think that PyPI being clustered with software that is documented and has tests is actually not that bad because most software that I see on PyPI sadly does not have tests and does not have any documentation that, uh, and that it's really not accessible to a lot of folks. It's poorly written documentation and maintainers struggle to keep up with documenting things for this reason because they go to a separate file, make documentation, the documentation becomes out of sync with the code. Even if you're using a system like Sphinx, it's a kind of pain in the neck to do all this stuff and maintain your test, maintain documentation. This is just one easy to use stream of thought. And there is a, as you can see, it was not like I just pushed a button and used nbdev. There is a barrier to entry. I have to learn it. I have to learn these commands. So I don't think it's— you have to be motivated to use it. So I'm not really concerned of some spamming pipeline for sure.
Great, thank you so much. Well, I really appreciate you walking us through. I know it's challenging to push everything, you know, all the rich content in a short 45 minutes demonstration, but I think the high-level takeaway for everybody is just how exciting in terms of coding, or that can allow us to do everything in one place and really streamline testing, documentation, and publishing your information out in really, really light touch, right, without having to get get into the whole software development side. So that's definitely exciting. I think a lot of people are excited about what they're seeing today, a lot of questions. So there's definitely learning that we can all take away after this, even after this event. So I'd like to have this Q&A session with you, and we have some questions, but certainly I can see we have a very active you know, chat here. So I will make sure I'll keep checking in here and, uh, and see if there's a specific question for you. But overall, it seems people are excited.
The creator of MBdev is actually in the chat answering questions right now, so that's, that's really cool. Hi, Jeremy! I know you might not be able to say hi back, but thank you for coming.
Yeah, thank you very much, uh, Jeremy, for helping me, uh, divide and conquer with some of the questions are quite technical and able to answer right on the spot and keep Hamel Husain moving on the demo here. There's an interesting code just following along the line of nbdev. Emily asked, "Can you talk about how you go to production with nbdev-generated code?" Almost like a tag-on, right? How have you seen code using nbdev being leveraged in a production environment, being a scalable solution, even in a business context?
Yeah, so as a user of code written by nbdev, you don't have any idea that the code is written in nbdev because it all compiles— compile might not be the right word, but I'm going to use the word compile— compiles to Python code, regular Python code, it was just pip installable. If I'm importing fastai, if I install fastai, import fastai, most people don't know that fastai is written in nbdev. Most people are totally oblivious to that and that's actually a feature, that's great. You can write your code this way, use it in production. My experience is that when people use nbdev, they actually write a lot more tests and actually write a lot more documentation. It's a virtuous cycle where the more you document the code, the more you're thinking about the code. I often find that when I'm documenting code and I find it very difficult to document, I realize this code is too complicated and I refactor it. Doing that in the notebook iteratively, documenting your code, while writing tests and writing the code in the notebook environment where your code is live, actually, it lends itself to much higher quality software. So that's my experience. I actually recommend it. It is a, it is a different way of doing things. But I suggest give it a try for those reasons.
Yeah, that makes sense. Documentation also has a lot of knowledge transfer, right? So somebody else can take your information and build on top of that. So kind of going through that process and almost self-evaluating your quality of code and scalability of code is definitely a good approach to programming. That's a great answer. So just wanted to get to know you a little bit, right? We're kind of fast diving into this demo, learning about the MBDAP, which is great. But you definitely had a very interesting journey, so to speak. You started from the law, pursuing the law degree, and changing into a data science side, and really running with that. So can you maybe share what changed, you know, that trajectory or what triggered that career move?
Yeah. So, um, the, the honest answer is I'm a type of person that I get bored kind of easily. I like to keep learning new things, um, and try to reinvent myself every so often when I find that you know, I'm bored of a certain domain. That hasn't happened with— well, it kind of— so it actually has happened a little bit with machine learning. But yeah, so that's what kind of led me from consulting to then law, but then I realized I really hated law. And then I went into data science. And then more recently, I've been more interested in software engineering. And that's something I've been studying, particularly in the last— starting in the last year, maybe 6 months or so. I've been going on this journey, particularly with folks like Jeremy Howard, who are excellent software engineers, and just learning everything there is to learn about that. And that's also— came across nbdev for that purpose. So that's kind of what motivates me and sort of what drives this journey across different domains. It's just a curiosity, really. Yeah, yeah.
Um, what do you see as the future within the data science industry? I mean, I think we can all say you turn a corner, um, you see something new, right? I think just the whole collaborative spirit around programming and data science, it's also able to accelerate these new discovery, new enhancement to what we do on a daily basis. So what may be your prediction or what you see as a trend for the future of data science industry that you could share with us?
Yeah, so I think one of the biggest trends I see in the data science industry is a focus on infrastructure, tools, software development. There's a you know, a lot of people have struggled to get value out of their machine learning systems or their data science systems, and they've been stuck in maybe prototype phases or proof of concepts often. And businesses really struggle with utilizing these models and kind of integrating it into their products. And so one of the things that I see gaining a lot of traction is sort of how to bridge that gap of— and they— those things, you know, occupy different dimensions. So there's one dimension of let's create better tools for data scientists so that they can, you know, do things like serve models or, you know, make data products. But there's also another trend of also data scientists learning about software engineering and incorporating some of those practices. And, you know, that's something that fast.ai is actually researching right now, is how to perhaps go about that education. I don't want to foreshadow too much, but, you know, I see that trend happening everywhere, the importance of software engineering in the practice of data science. That's, that's what really allows you also to stand out as a data scientist. I think that's something unique you can bring to the table that has immediate value from day one if you know how to write software.
Well, that nicely transitions to my next question. You may already answered it. What are some key criteria to make a data scientist, especially early professional or early career data scientist, to be successful and also effective?
Key traits. Yeah, so I mean, I think the main thing is curiosity and willing to learn. And that sounds very generic, and I know it sounds kind of, you know, doesn't really sound like a great insight, but to really do that correctly is very difficult, most people don't do that. You know, if you see something that you don't understand, you're using some library you don't understand, or even using Python, you don't really understand like why it works the way it does, just diving deeply into it and kind of figuring out how things work, that really goes a long way. And that mindset, I think, is the most helpful thing to being successful. I think it's more important than any degrees that you might have or any formal training that you can get. That mindset is, I think, what sets— what allows people to be successful.
Just stay curious and take things apart and put it together. So really understanding the why. I think we had past speakers sharing this year with our students is that, you know, it's important to understand the fundamental and basics, right? A lot of time we can run really fast, but continue to carry that curiosity forward in everything that we do, it will be really successful.
Yeah, and it's also important to have an open mind to new things. It's really— it's really tempting to say, hey, like, this new thing is too crazy, like, I'll never use that. But I think it's very helpful to explore new things. It really opens your mind to different ways of working and different tools that you can use. Things like, like nbdev, for example. I think even if you don't use nbdev, I think it's really interesting to experience it just for the knowledge of what a workflow could look like. I think that experience, that way of thinking is very helpful just to add to your sort of toolkit.
Absolutely. So we definitely have some good questions coming through, so I'm going to take a pause here. Shane is asking, is dynamic typing a requirement for literate programming environment like nbdev?
That's a good question. I know that literate programming, being able to inspect variables on the fly and things like tab completion that you can't get in an IDE. Because you actually have to evaluate the thing that you're running and be able to play with it is really important. Now, I don't know, I mean, I have to think about it more deeply if that constraint that you mentioned is necessary or not. I actually don't know, to be honest with you. One of my limitations is I've only programmed really in one language, so I don't really know you know, just R and Python, and I'm learning some other ones right now. So I would say that, yeah, I don't know the real answer to that question, to be honest.
That's fair. So Joseph here is having a question around if you can clarify if fast.ai deep learning models requires MBDav. Just so used to separating machine learning from development.
No, you don't really— to use fastai, you don't need nbdev. Again, nbdev is just used to write fastai, but to use it, this doesn't require that. Now, if you wanted to contribute to fastai, you wanted to, you know, change some code in the library, contribute as a kind of open source contributor, then you would need to learn nbdev because that's what it's written in.
Great. PyTorch ties us to Python. TensorFlow works with Python, R, or JavaScript. The question is, is that a reason to go with TensorFlow rather than PyTorch?
Yeah, so I don't want to get into the PyTorch versus TensorFlow religious debates. That's kind of an area that is hard to talk about with a lot more nuance. I will say that, you know, there's— yeah, I mean, like, I don't have a strong opinion on whether you should use PyTorch or TensorFlow. I would say, you know, there's a lot of considerations that go beyond— I mean, this idea of what is the best library in abstract versus what is the best library for your situation is quite different. What are your teammates using? What's your company using? Do you have constraints that you need to— I mean, oftentimes, like, I have to— you have to look at the practical side of things and see what works for you. I mean, yeah, it's hard. That's the best advice I can give.
Right. Perfect. Another question. How should one go about extending mbdev? To add co-profiling features for efficiency or performance reasons? For example, if I'm writing a preprocessor, is it possible for me to add automatic co-profiling tests to nbdev?
Yeah, that's actually one of the things that we would enjoy a contribution on. And that can take the form of many, in many different thing. So like you can profile code right now if you're writing in nbdev because again, I mean, it's generating real Python code, so it's not this new thing. It's, it's just a way of writing code. So you can use your profiler, but if you wanted a profiler in the notebook, there are some options for you, but I don't know if any of them are really that good. The notebook profiler, the add-ins that are there. I think there's an opportunity perhaps to write better profilers that can work inside notebooks so you don't have to leave, if that makes sense.
Thank you for all of these great inputs, and I really appreciate all the questions, um, from the audience. So, okay, I'm gonna And with one more question from the audience, what books, resources would you recommend for data science folks with less of a computer?
Yeah, computer science. Yeah, I would say look at fast.ai, best, best resource can go to. Doesn't, you know, it doesn't assume anything beyond high school level math. You don't need a comp sci background, and you'll be— yeah, it's the best resource.
Great.
And someone commented that fastai also has a book, so that's also amazing.
There you go, even better.
Great.
Well, thank you so much, Hamel Husain, for spending the night with us, with, you know, a lot of data scientists, enthusiasts from MSDS program and even external guests that joining us tonight. So really appreciate your time. Thank you.
Thanks.










