 Everybody, my name is Rick Harding, also known as Hopalong Harding, as you may note, as I wheelie around the conference room here. I can stand as my doctor's gonna yell at me till I get my ACL fixed, cause I shredded it. Showing my bike, my son had a wheelie. So I am like all kinds of, I am the intelligent person you wanna listen to when it comes to all this stuff, so. All right, so, you have an API now what? It's time to work on some clients. I apologize, now I'm gonna ask you to do a bunch of work, but I'm gonna justify it. I promise, it'll totally be worth it. So why should you listen to me at all? I spent a bunch of years, five or six or so, working on an open source, delicious clone web app thing, and got me into Python, and built a community, and wrote APIs on clients and phone apps, and did Google Summer of Code, which was excellent. If you ever get a chance to participate, go do that. I've also worked at Canonical, the people folks behind me, a bunch of stuff on their Juju product for the last few years, but I'm coming up on six years there this November, so I've been around a few blocks, I've done a few things. I'm a father to this awesome little guy who I was trying to show how to do a wheelie, and I should never try to teach him to do anything ever again. On this bike, I like to mountain bike, I like to camp and RV and everything, and I like to do photography and travel, and so that's me. Great, no, who wants to go next? No, sorry, that'll take a little bit. So why an API? Why do we do APIs to begin with, right? And I always, for me, I've kind of over time transitioned into kind of a very product manager-y view of things. I care a lot about community adoption. I mean, why do we write code? We want people to use it, right? We want to do useful stuff, and especially open source code, we just want, we love when that someone comes along and goes, your tool solved my problem, you're amazing, and then we go, yeah. And then we go tell our significant other. They said I'm amazing, and then she said, yeah, wash the dishes, you know. So, but the thing about APIs is they're there to do things like provide robots to go and do things while you're sleeping. They're there to provide features of things, you know, you don't have a button on your website for it yet, but the API lets people go and get their work done. APIs, I love APIs, I could talk about how to do them and what they should do and how they should look and feel, and APIs are just an amazing thing. They let people build products on top of your product, you know, letting you get exponential adoption of your tools and becoming like vital infrastructure. You go from being a tool with an API to an actual platform, people are building their own products on and there's something really special about that. So I love APIs, so that's great. So what do I mean by client? So APIs are great. How many folks here have written an API, provide a service that has an API on it? All right, how many of you all have written tools to use an API by someone else? Okay, now how many of you actually make raw calls to the API or how many, so raw calls, no library? You didn't pip install Bodo, you didn't go download the Stripe API client or whatever, you just make raw, exactly, right? The numbers there were about, I don't know, five or six to one, right? And the point about clients is a client is basically a library written in a specific language provided to users of that language to embed in their own tools. So example would be, I'm gonna talk a lot about Bodo. Bodo is a Python library that AWS funds a developer to work on so that if you do any work in your code against AWS, you have this lovely Python package library that handles all the fugly XML that I don't ever, ever wanna see. Cause it's written very Java-ish with very complicated, like to do the raw queries to AWS, I want to just quit and go become another job that I will probably install. Anyway, so I'll let it go. So it's un-good. So I work on this project, Juju. We learned some of the lessons I'm gonna go through here. Very, very hard. So we have Juju's a tool for doing operations at scale and cloud and bare metal and such and a very, you know, modeling your operations really well. And then it's got an API. We stand up a server and it's got an API. It's a web socket driven API. You issue commands across the web socket and it's very nice cause it's real time. You've got an open connection and all that. But because of that, it's not a simple just post this to this URL and you get back some, you know, JSON response. So, you know, we have this API and that's great. But you know what we found? Most people actually did it first. They grabbed our CLI and they write shell scripts around it. So one thing you may not realize is you've got an API, that's great. But people actually start out on the smallest, simplest thing they can do, which oftentimes is just a shell script that for loops through and does stuff. So I want you to think about not just, well, I have this API served by a server, but look at this as in any way a user can leverage your product or tool. They're all APIs of a sort, right? And so in our case, our CLI is, you know, we spend a lot of work from juju1 to juju2 to revamp the CLI and make it much more usable to care about it as an entry point. But it's interesting because we wanted people to go, hey, you can script this against the API and they would go, yeah, well, how do I do that with the CLI? And we're like, oh, well, no, you don't do that. That's not made for that. So it's very important to have the API because they were falling back to the easiest thing they could do. So in juju, you deploy software, okay? jujuDeploy is a command and it's one of my favorite ones because the CLI actually has a baked in go, juju is written in go, the backend services and the front end CLI client. So it has a baked in go client library for the API. And when you do jujuDeploy my SQL, the client actually does a look up to an API that says, okay, tell me, what is my SQL? The user's asking for this. And it's kind of like DNS. It resolves my SQL to an actual charm store, like identifier URL path in the API, sends that back to the client. The user never sees it because it's big and ugly and we don't want them to have to type it. It then sends it to the server and the server goes, okay, I know exactly I have a URI for this thing and I can now go and it runs an API call to add the charm into the database. Then it runs another API command to deploy a unit on this cloud that you specified. So jujuDeploy kicks off dozens of things that happen from fetching resources to bringing up cloud instances to configuring things and triggering scripts and hooks and all that. But the user just goes, I tried to deploy and it didn't do what I wanted to do or whatever. And you're like, well, okay, that's complicated story. So this is one of the things I really want to emphasize. Oftentimes when people first think of clients for the API, they print out all the API commands and they start to write a client that has a function for every one of them. And that is not a good user experience. I would like to encourage everyone to never ever do that. That's evil. You ever hear don't ever write your API so that it's basically database operations? Like don't make your API a map of database calls to your database, because that's not helpful at all, right? Put some thought into what your product's actually offering and how it works. So oftentimes people go, hey, I've got an API. Great, the community will come forth and they will write clients and all their languages and they will provide for us and we will be awesome and amazing and be everywhere. So we did that in Juju. We're like, the community will go forth and the community did a great job except that they did many clients. And so we ended up with this kind of chart. Which client do you use when? Well, are you on Python two or Python three? Are you using Twisted? We have a library from a community person that did that but it doesn't work on Juju two, you know? Or it doesn't work on Juju one or Juju two. And so because we didn't own the client experience we left it to the community. We then had people come up to our mailing list and our IRC channels going, hey, I'm trying to script this with Juju to which we replied, so tell me a little bit about your environment. What are you trying to do? We can recommend like, I feel like a personal shopper. You know, I can find a suit that'll fit you. Are you going to a fancy dress or is this a casual thing? You know, like which one's right for you? And so this really led to some issues and really what it needed to be is we needed to take more ownership of that. The other side of this is we've had this API but people haven't gone in and adopted it and really used it for things we wanted them to do. We often tell a really good story of how you can use Juju and our tooling and our charms for a really thorough CI CD experience where you can match the application code to the operation code and test it together. And if you have new application code you can do testing and it's all scriptable through the API but it was a lot of work and we really didn't find people were doing it. They would do things the old fashioned way, manually testing and all that and we were frustrated. We've provided you the tools to do this. Why don't you do it? And what we weren't hearing but we should have heard was because it's still hard. So I compare it to packaging. Long ago in my open source days I worked with, there was a developer that wrote a tool for a bunch who called Nome Do. It was like a quick silver launcher thingy for Nome. And I loved it. I've been looking for it coming from a Mac to Linux. I used it up but you had to build it yourself. And as part of my, I want to learn how to do packaging so I packaged it into a PPA and suddenly we had rather than like five of us hacking on this project and working on it, literal tenfold increase of users like week after week after week. And this is like one of my first insights that the ease of getting something to your users is you can't overestimate it. The adoption will come up so much more if you provide a client that works smoothly with your current version in a way that does good things your users will come. So this all comes down to really owning your product. I always love how Git is this tool but GitHub's kind of become the product in a sense. As you know that there are pull requests is this term that everyone uses now use pull request everywhere for everything. It wasn't actually even anything really in Git there was no such thing as a pull request until they added this Git request pull command which came out in 2014 which if you know Git goes back further than that and it's not even pull request, right? But we all talk about pull request because the definition of what is the vocabulary there has been defined by like GitHub. In Juju 2 we spent a lot of time going through and we wrote down and all of our on our product you create a vocabulary. What does it mean to speak the language of cloud computing or container computing or in data science or whatnot. There's a vocabulary you have to learn to participate in that community. So your product defines you know what does it mean a car for instance? You know you've got is it four wheel drive or not? Is it rear does it you know does that locking rear diff or front diff and all these vocabulary things you have to learn to participate in automobiles or whatnot. So we broke down what are all the verbs and nouns that are used in using Juju and that appear to the user that they need to understand how do we limit them and focus them and as we build out our product, our API, our clients we make sure we're very consistent that the language is the same. The API call is not get charm and then the you know the client says deploy app right because those two things would be different. You know we don't want to have that difference between your product. So thus was born an official Juju client. We sat down and wrote and we have it it's in PyPI now you can go get it. This is official it's you know version two one of the things that was really important to us was this is for Python community so it needs to use the Python standard best practices. We have data to use async IO. You know we don't use twisted and stuff in it and I go back to the Bodo was a really interesting example because this guy in the community cared a lot and wrote this client and AWS came along and realized clients are important to the people that use our product. When someone uses a client they're not actually they don't care what the API looks like. They never see it right. All they care about is the client experience and that's whether or not the user thinks your product successful or not is gonna be based on the client they use. Is it easy to use this in my code or is it hard? And that client maybe you know covering over five different API calls that had to be made in complicated ways in the background but they won't care if they don't have to deal with it and see it because they did a good client. So I really love how AWS they actually hired up the folks doing the best clients in a lot of the languages and put them on a tools team because AWS cared about providing a consistent up to date experience in those clients to their users. So when you do these clients you have to take in and kind of pull in the values of those languages. If you're doing something in Go it needs to be very lightweight. It needs to be easy to incorporate from their methods pulling straight from GitHub with a packaging tool that they use and care about if you're doing something in Ruby or JavaScript it needs to be very modern JavaScript ECMA 6 compatible using promises or all the latest things that that community expects. And by owning the client you get to enforce best practices. You get a good benefit. You get to make sure that when they use the client logging is set up properly that resources get cleaned up on failure conditions that it's doing things like reusing connections and not abusing your API by spawning thousands of connections because they did something silly. And you get to send useful product data. You know what version is the client making the API request? We often go through and look at how well people are keeping up to date with the latest clients. How many people are using old stuff? So the client automatically sticks extra metadata in the API calls that then we can use to collect useful information about how are they using it? Are they using it from one set of computers or on this cloud and not that cloud and all that kind of stuff. It's a great opportunity to really again not just own the product experience but then benefit from that use. Some more examples. You're not limited to mapping exactly the API to the end user and the client. You can completely mask over warts. You know man, if we change that in the API we have to version it and release a new version then get everyone to adopt it or we can update the client and have it do a little magic foo and kind of smooth over that little wart in our API and the users actually get the better experience. And especially encourage folks in the world of microservices and all that is to have a single client. Notice that there's one BOTO API client for AWS. There's not one for S3, one for EC2, one for whatever. You can develop things in a very microservice easy to update and manage and scale world but still provide the end user. We are a single company with a single product with a single way to interact and use us and users will enjoy it. So it sounds like a lot of work and it is. I promised you I was gonna convince you that it's good though. But there are things that you can do. Use your own client but don't do it like we did. Our command line has an embedded go client. How many people can go and use that embedded go client? No one because our CLI is embedded into it. You have to get the CLI and we would cheat. The CLI had then, it had access to internal code because it imports a bunch of stuff. It wasn't a separate product. So use your own client but make sure it is distinct. Treat it like an external dependency in all your use. So you do a CLI, use your client. You build a web UI. We have a juju GUI that uses a JavaScript. We didn't do this well or we kept a separate JavaScript client and treat it as an external dependency. And then use it for your own internal scripting. Your QA, your Jenkins servers, all your CI infrastructure. Script using your own client. And you'll find that you could actually get a lot of client use, written testing, adoption and ease a lot of your burdens internally without feeling like you're paying someone to go write these clients independently as their own kind of products. You kind of get the little two for one snack there a little bit. But you have to go through a little bit of self control to do this. So with that, I'd like to just kind of show that it's not just me, I'm not crazy. AmongoDB, you can see they've got the list of clients for different languages. This is from Sentry, which is a tool they want you to send your logging and stuff information to. They provide clients in a bunch of different ways. There's Stripe has clients they provide in Ruby and JavaScript and such, as well as AWS with their clients themselves. So I really encourage you to kind of own your product, focus the community. They don't spend time writing the clients or if they do write a client for a language you can't focus on, you can at least direct them and guide them based on the clients you've already provided. We've established best practices, how things should work. The community has to do less work of reinventing their own wheel. So you can really focus on them. And then where you go from here, just go out, provide the best product you can to your users, think about things and go through the little bit of extra work to keep these clients external to your own tools. And I think you'll find that you're off in a much better place to get adoption, drive usage and get really good feedback on your APIs. So I just wanna say thank you. I particularly wanna call out thank you, Pi Ohio for 10 years of awesome stuff. I've been coming here since the very first one Catherine did at the library. I've spoken at a bunch of them now. And I just love, I've met a bunch of people that this was their first one or their second one and stuff. So I think I just wanna call it. They're doing some awesome stuff here. So support Pi Ohio. Any questions or anything? I'm the guy trying not to run over your foot in the wheelchair as I try to stay off my knee and prepare for future wheelies. But otherwise, thank you very much. I do have a few minutes. Any questions, I guess? I wanna make sure I don't run out of time. Question in the back. So that's an interesting one. So, oh sorry, yeah. So do I distinguish between a client and an SDK? And yeah, so I mentally this and I should look at a formal definition somewhere. When I think of SDKs, I think of like baked in editing tools that tend to come down. Like you think of like the Android SDK or whatnot. You get a suite of stuff to stick with. Whereas a client is merely a library. So I think that's where I would limit it. If it's just a library I can import into my code and whatever I wanna do, that's just a client library, right? It goes off and does some work for me and whatnot. But an SDK feels like it needs to be a bit more than that. It needs to have more tooling for bootstrapping, shell projects that are started off or things like that. I would consider those more SDKs to do more than just provide an interface to an API. So, again, because we're doing, okay, what is my opinion on versioning the client versus the library? And this can be contentious, people believe different things. My firm belief is we're all following semantic versioning, right? So if I have one dot and two dot, right, and I write something in two dot, it should pretty much work in two dot, even two dot, two dot three. There may be new features available, but I should be able to use a two dot one library against two dot three on the old stuff and it should just work, right? Otherwise, I broke compatibility, major compatibility, and I should go to three. So my thing is that as long as the client library and the API version match in the major version, I don't care about the rest of it, right? The rest of it's all for change logs, figure it out, bug reports, targeting milestones or whatever. But you do have to, if you break something, just be honest and rev that version. I will say one of the biggest things I can ever say is if you do anything, if you do any API stuff, start with version right off the bat, no matter what, and try to do everything in your power to make it so that you can rev the version, because I have seen so much technical debt accrued based on going, well, if we did the right thing, we'd have to rev the version, which would have all this fallout, therefore, we're not gonna do that. Instead, we're gonna do something really hacky that no one wants to do, that we're gonna have to maintain for a decade. That stuff makes me cringe. So I even encourage, when you first start doing APIs, intentionally find ways to rev the API early and often so that you've established a practice. How do we do it? How do we announce it? How do we provide a client that talks across these versions? You want your client to come down and basically maybe you have to put it in compatibility mode, or even better, you have to, normally in a client library, you have to say, here's where the API endpoint is to be able to have the client detect what version it is based on what URL you give it. So if you have a suite of microservices, you could have ricksjuju.com slash two major version number or something, right? So that from there I can see then all the different microservices and they each have their own individual URL segment. So your URL may actually be four parts, right? The root domain, a version for the major thing, a subcomponent or a microservice component and then its version that it's currently sitting at as deployed currently. And then the actual rest of the getting work done part of the API string, you know, such that you've got malability in there to update things as you need to. Can I compare my client and plugins? Plugins, I always define plugins as things that adapt behavior to a tool like you can optionally put it in and put it out. A client implements an API, it should do it fully and completely to where users can do whatever they can do with the API so I don't really compare them as the same thing. All right, thank you very much everybody.