 Hello everyone, my name is Zohar, I work at Red Hat and I want to share with you the story about how I broke our CLI, but more importantly I want to share what I learned from it. So I work in a team called OCM that stands for OpenShift Cluster Manager. It's a service and that service allows our customers to install OpenShift clusters on AWS or GCP. So apart from that service we also have a CLI too. CLI 2 called Rosa stands for Red Hat OpenShift on AWS and it applies for a subset of the features that are supported by our service which is very specific to AWS and users bringing their own cloud account. So our service maintains a cluster lifecycle. When a user requests to create a cluster, initially the cluster will go into waiting state where it waits for the user to complete some configurations. Once the configuration is ready and everything is set up, cluster goes to installing state and when the installation is finished the cluster is finally ready. Now I wanted to enhance the service and add another state which will perform some validations inside the user cloud account and prevent later installation failures. The problem is our CLI was counting on waiting state initial state. So I went home, tested everything on my service, had it reviewed, had it merged, everything was great. Next morning I found out CLI is broken. So I said okay I can fix the CLI. It was a small check, what's the initial state, remove that check, fix the CLI. But then I realized I have to create a new version and ship it to hundreds of customers. Now the problem is customers are not so happy to upgrade their CLI to and I definitely can't force them. So at the end of the day I had to compromise and I had to implement the validating state after the waiting state. This is not the optimal solution. This is not what I wanted to get but that's the compromise I had to make. Which led me to think about this talk. So how do you build a service-oriented CLI? First question we want to ask yourself is why do you even need a CLI? I mean you have a service and it's restful and you can do anything with your service. Why do you even need another CLI tool? So eventually it all comes down to user experience. And I'll give you examples. First thing we have a complex service. So our service allows users to configure cluster creation on Google Cloud using Red Hat Google account or the user Google account. AWS using Red Hat account or the user AWS account. So we had a growing share of users wanting to bring their own AWS account. So we decided that for this, for those users we want to simplify the problem. We don't want them to go ahead into our service and configure all the parameters. We just want to give them a simplified solution. Another example, whenever you go and want to use the service on every API call, you need to provide an authorization header with your token. You need to provide the full service URL where if you work on a CLI tool that sits on your machine, you can hold your credentials or refresh your token locally. And with one command, a login command that also supplies the URL, that's it, you're logged in. You don't need to deal with that anymore for the entire session. Okay, another thing, restful commands, that's nice. But human readable commands are much nicer. And you can use names instead of IDs and describe and edit instead of get and patch. What about the output? So you can get this big JSON with all those fields. Or you can get a nice YAML again in a human readable form. The input, you need to provide a JSON body or just give two nice parameters, two nice command line tool flags to your create command. Another great thing about CLI is interactive mode. Interactive modes allow you to validate users input on every flag they put in. You can have autocomplete. You can also provide a list for your users to choose from. So those are really great things that CLIs allow you. So where does it get complicated? Let's consider that we want to add a new functionality to our product. In our case, I'll take the functionality of as I shared with you before, users have to configure a few things in their cloud environment for us to continue with the installation. So we wanted to automate it for the users. So should we add it to the service or should we add it to the CLI? So it's very tempting to add this to the CLI because this is a very specific Rosa use case. So it doesn't, it's not interesting to other customers of the service. Another thing is that the CLI is a very small piece of code in comparison to the service. So it's much easier for a new developer to get in, put that small change inside the CLI. No need to get inside a lot of service logic. No need to worry about getting it merged with this big service. However, we have other clients for the service. So if we go ahead and implement that in the CLI, we also have to implement that in the UI or any other client that we have. Another thing you want to consider is the key difference between a service and a CLI tool. So while a service has continuous rollouts, it's continuously evolving. It's always there in your cloud. Whatever you want to change in it that doesn't change the API. Let it be a new small enhancement or a bug fix. You just roll out a new version. You can do it weekly, bi-weekly daily, and it's there for everyone to use. But a CLI tool, it's not in your environment. It sits in your clients environment, customers and every new functionality, every bug fix, that's a new version. And every new version could be a very long release cycle because it has to go through compliance and other internal company processes before you release it. Another thing is that customers are not so happy to upgrade their CLI or any software that they have because it also has a process within their company. And another thing to consider is that every version, you have to support it for a while and you might find yourself supporting multiple versions. So to sum this section up, you want to maintain a thin CLI. You want to ask yourself, could other clients benefit from the functionality I want to add? The answer is yes, you want to put it in the service. What if we need to enhance it? What if we find bugs in it and sum everything up? You want to keep minimal business logic inside your CLI. Okay, let's go back to the first example I shared with you about how I broke the CLI. And let's try and think how that could have been avoided. So first thing you want to ask yourself is like as a CLI developer, what can I rely on? What assumptions can I make about the service that I'm using? Because we have a contract, the service exposes a contract, that's the API. But there is so much more beyond the API, like other behaviors, like the initial state that we had. And if you think about it, you might stop yourself from making decisions that will limit your service from enhancement. Another thing you need to think about is your vision support policy. So you want to carefully define how often you release a new version. How many versions are you going to backward support, like define, I don't know, two minors, three minors, and have that policy known to your customers. And whenever a version is going to get out of support, you want to give your customers enough time to prepare for that. You want to notify them. Last, but not least, you want to have automated CLI tests. We had automated tests for our service, really with big coverage. We didn't have a lot for our CLI. If we would have tested our CLI most common use cases, we would have definitely caught that earlier. So that's, you want to put the CLI inside your CI process to sum everything up. You definitely want to write a CLI to improve your user experience, but you want to keep it thin and minimize the business logic inside it. Always, always keep in mind future service enhancements. When you go ahead and make assumptions about your service, define a version support policy and have automated tests for your CLI and have them running continuously. That's all I have. Any questions? Okay, great. Thank you.