Las Vegas 2018

Taking Ops & Infrastructure From Iterative to Functional

Cornelia Davis is Sr. Director of Technology at Pivotal, where she helps customers develop and execute on their cloud platform strategies. Responsible for guiding clients on the technical elements of broader transformation, she helps development and operations teams, and IT executives understand and adopt new systems, platforms and processes, as the central part of delivering greater value to their customers. Fundamentally, Cornelia helps enterprises shift from a mindset where IT is a necessary evil, to becoming software-driven businesses with IT at the core. Finally, through these deep engagements with clients, Cornelia also brings valuable insight back into Pivotal, driving advancements in software and services offerings.

CD

Cornelia Davis

Senior Director of Technology, Pivotal

Transcript

00:00:02

So to introduce the next speaker, uh, Cornelia Davis. I'm gonna do something a little strange because I'm gonna talk about me. So, you know, I've been studying high performing technology organizations, uh, for since 1999. Um, and so even though I was in the information and security compliance space, um, I was a trip wire for 13 years. Um, I actually identified not as a security person. Um, and despite the fact that I was formerly trained as a developer, I got my graduate degree in computer design. I actually self-identified as an ops person. And because I think that was where the action was at, right? You know, who is, you know, saving the customer and the company from all the sins of development operations. Where's all the action happening? Operations, right? Where, you know, uh, so where all the saves happening, operations. Um, but something has changed, uh, some.

00:00:47

And about two years ago, um, I actually self-identify not as an operations person. And that, by the way, that's sort been 20 for almost 20 years. Uh, I now self-identify as a developer. And I think it's because, um, of, of a computer language I've, I learned called closure. So it's a, um, it's a immutable functional programming language. You know, it has some very strong, it's, it's a lisp language. And what I found was that, uh, by learning this, and by the way, I'll have to say this was the hardest thing I've ever learned, uh, I think in my career, right? I probably spent 60 hours reading before I could write one line of code, right? It, uh, I mean, it was that hard. And yet I found it to be the most rewarding thing, uh, I've ever learned. I think that one of the manifestations of that is that, uh, 90% of the mistakes that I had made in my career, uh, just disappeared.

00:01:34

It was made impossible, you know, because of immutability, uh, because of, um, uh, you know, these various functional programming, functional purity. And so, uh, here's how it's impacted my daily work. Uh, I used to say that on a good week, I would spend half the time hanging out with the best in the game, right? That's I people like you in this crowd, right? This community, and then half the time writing. And that's changed on a good week. I'd like to spend half the time hanging out with the best in the game, half the time, um, writing and then 20% coding <laugh>, right? And because, and I really, it's really brought the joy of, uh, coding back to me. So, uh, by the way, if any of you have used closure or functional programming, uh, ping me on Slack. I would love to talk with you.

00:02:18

And in fact, it's because of this that we actually moved Scott Haven's talk, uh, to today, and I'll explain why. So, uh, let's talk about why Cornelia. Uh, Davis is going to be talking to you today. Um, she almost got her PhD in language design. She's been a part of the program committee for three years. And one year ago in London, uh, we were talking about, uh, you know, something, and we started talking about how we both loved functional programming and lists. We talked about concepts like immutability, composability, decorative modes, uh, and how it applies not just us for development, but also infrastructure as well. Uh, because if infrastructure is code, that means infrastructure can be made radically safer in the same ways that has drastically changed, um, the development community. So I'm so excited about this talk because I'm pretty sure you've never seen a talk like this before. We, I asked her, can you teach us about how important functional programming is to development widely considered to be in, in a just world, right? It would be considered the next breakthrough since object origin programming, uh, and infer how those lessons learned in the development community will be incorporated and are being incorporated into infrastructure and operations. So, um, Cornelia and I have been working on this presentation, uh, for almost a year, and I'm so excited about what she has to share. So with that, Cornelia Davis,

00:03:36

Good morning everyone. Thanks so much for that, Jean. Um, it really has been a pleasure for the last year or so to be, uh, noodling on these topics. And, and I hope you find this useful. It's a chance for me to be a little bit of a geek. Um, not that I don't do that on a regular basis, but, uh, let's go ahead and get started. Um, so to tell you a little bit more about me, um, Jean already kind of alluded to this. I did my bachelor's degree in the greater Los Angeles area at a school that was really focused on getting people ready for industry, very pragmatic. I learned a lot of different programming languages, and we'll talk a little bit about what those programming languages looked like in just a moment. Um, so that's where I started, was at Cal State Northridge.

00:04:19

Then I worked for a number of years and said, ah, screw this work thing, and I'm gonna go back and I'm gonna go back to school and get a PhD. I, uh, left Indiana before I got my PhD, so I'm a BD all but dissertation. Um, but Indiana University was very, very different in that it was, um, not in the greater LA area. It was not in Silicon Valley, it was in a small town in southern Indiana. So it's really a very much an academic research oriented university. And there I studied theory of computing and programming languages. So really the mathematical underpinnings of it. Today, I work at Pivotal. I work really on product strategy. I work on emerging technologies, and I have the great opportunity of working with a lot of our clients to take emerging technologies and figure out how those emerging technologies can actually bring value to the businesses.

00:05:14

Um, as I, I have been a developer by background, my, pretty much my whole career. And when I came to Pivotal and started working on platforms, I realized that they weren't just about development, they were also about ops. So I actually self-identify as a developer, but consider myself almost as much an ops person now as I do dev. And then the other thing is that you can see here is that I, I, because I have so much free time on my hands, a couple of years ago I decided to write a book. And so I've been working with Manning on writing a book called Cloud Native. It's an architecture book, but with lots of code samples. So the code samples are in Java, in imperative programming, language leading into the things that we're gonna talk about. Now, let's start with a little bit of a history of, um, computing.

00:06:05

How it started. In the beginning, we had very simple programs. We had single threaded programs. And in fact, I started my career in aerospace where I worked on embedded systems on missile systems. So we didn't have multiple processors, we didn't have distributed systems. It really was a single threaded system. And there was, you know, when I programmed against that, then we ended up with multi-threaded systems. And then that, um, expanded into MULTIPROCESSOR systems. So all of our, even our phones probably have multi-cores on them. Certainly our laptops and our workstations have multi-core. And then in the last 15 years or so, things have gotten highly distributed. So it's not just that we have multiple things going on on a single computer. Our software, our digital offerings are spread out across the internet across lots and lots of different nodes. Now, if we take a look at things from a programming languages perspective, I actually did some assembly language programming, not only in school, but a little bit at work.

00:07:08

Um, I also programmed in Fortran, even did cobol. Yes, I am that old. Um, then we started moving into higher level languages like CC plus plus Java, and more recently Golan. And what's starting happening in the industry is I'm starting to see people pick up other languages like Scala and Closure and Kotlin and F Sharp. My customers are telling me that their, their developers are programming in these languages. Now, if I reflect on that, it's a very interesting thing. If we look at those earlier languages, these are all what I would call imperative languages. And I'll explain that more in just a moment if that's not familiar to you. These other languages that we see at the bottom here are functional programming languages. And so that's what I wanna study in the next 25 minutes or so, is the difference between imperative and functional. What are the benefits of the latter over the former?

00:08:08

And then most interestingly, how do we apply this to ops? Alright, so lemme explain imperative and functional programming with a concrete example. So I am the luckiest mom on the face of the planet in that my son decided to go into technology as well. And he just graduated with a degree in math and computer science. And earlier this year, he was, um, in a class on, uh, genetics. So it genomics. So he was doing, um, machine learning and, and those types of things. And one of the problems that he had to solve was they were doing gene sequencing and they had to break down these very long sequences of characters into different segments, and then they would process the segments independently and then deduce some results from that. So genome sequencing, if you will. Well, when you broke up that segment into lots of little small pieces, there was this balance.

00:09:00

Sometimes the pieces were too small and that would skew the results. So after running the first algorithm and breaking the sequence down into smaller segments, he went through a process of actually merging the segments that were too small back into some of the larger segments. So what we see here are a segment of size five, another one that's about size 12, another one that's size three, and another one that's size 13. What we wanna do is get rid of the five and the three and merge them together. So ultimately we wanna merge those short segments together, and the output would be something like this. So let's see how we would write this little simple program in a couple of different styles. This first example is Python, and this is in the imperative style. By imperative, what I mean is that you as the developer, are controlling every single step in the process.

00:09:58

You are figuring out the sequence of events that you are going to program the system to do. And so you, what you can see here is we've got variables, we've got side effects. I'm changing the values in those variables. And without stepping the through the code in detail, roughly the algorithm looks like this. I've got a counter, I'm taking a look at the value of the nodes. I'm checking to see if it's too small. If it's too small, then I write over some of the values, and then I get rid of a node, shrink things together. And you can see on the, on the right hand side, the list length is changing in size. And eventually at the end, my counter goes to the end and I'm finished. And I get the right answer here. Now, the thing that I'll tell you is that that program, that short program that we saw in the previous slide, actually has a bug in it.

00:10:51

And that's in fact one of the things that's a hallmark of this, um, type of, uh, programming language. It's sequential. You control every step. We have variables with side effects because of those things. One of the things that happens is that we end up with hairy edge cases. That program that I showed you worked out only because my last segment was big enough. If the last segment had been small, I would've thrown in error. Those are the types of hard air, hairy edge cases that are hard to find. It's also d difficult to parallelize, which if you remember the picture that I started with, everything is in parallel. Now. Distributed systems are in parallel. Now, an alternative is written here in scheme. So that was the language that I did everything at, in, in when I was at Indiana University. So this is a functional language.

00:11:48

So what you'll notice here without going into the details, is let's step through what that algorithm looks like. We start with the same input, and basically the way it works is that I declare different, um, different conditions and different outcomes based on those conditions. So the way that I solve the problem here is I break it down into two smaller sub problems. I take the first part, I solve the problem for the small, for the rest of the list. I get that answer, and then I merge together. The first part with the answer that I got from the last part that's functional. Now, the hallmarks of functional languages are that they tend to be declarative. The way we program is declarative. That is, I'm not specifying every step that goes, I'm declaring my intent. We'll see where that comes back into just a moment. There's no side effects.

00:12:43

You'll notice that there was never an equal statement in there that assigned a new value to some memory in, in, in a location. And it's recursive, it's not looping. And there's a big difference between recursion and looping. And we'll see what that looks like. And the outcome of that, of this type of programming is that it tends to be easier to program in a way that allows for parallelization. There's fewer edge cases. And here's an important point, the comp, we can have systems do more for us. We can actually prove certain things about the correctness of our systems and we can have inference happen on our behalf.

00:13:30

So our very own Gene Kim described how he went through this transition himself. He started programming and he has a particular program that he shared with me that started out when he first wrote it years ago in objective C as 3000 lines. Then when he rewrote it in, um, types ripped and react, he it, it reduced in 1500 lines and now he's got it running in 500 lines of closure. So here's the point is the point is, what is the model that we use to reason with how can we solve these increasingly complex problems using a model of thinking? And that's what I want to talk about. So if we look at the difference between imperative programming languages and functional programming languages, there's really four categories that I would li list out on imperative. We go from iterative, I specify every step to declarative on imperative.

00:14:33

I go from mutable state side, effecting state over into immutability in imperative. I am looping in which I'm changing that mutable state. And on functional I do recursive. And then finally, maybe it's not so much purely functional, but on the imperative programming languages, we tend to compile libraries in and in fact, in some of those imperative languages, we've moved into a much more modern way of doing things like in the spring framework. Um, and we saw Mick who did his p did some of his work in a OP, um, we saw him speak on the first day aspect oriented programming. So it's not purely functional, but it is really relevant when we move over to the functional side. And as badass as she is, I am suggesting that this 82-year-old software developer, yes, I found her online. Is she not amazing?

00:15:32

Should yes, thank you, should not necessarily be programming every single element of her software anymore. Let's let the software do more of the work. So here's the thing, we cannot reason about every detail in our heads anymore. So we need a model for thinking that also allows the computers to do some of our work for us. Alright, with that, let's turn over to operations or as I'm gonna call it systems programming. So with systems programming in the, in the past we've had distributed systems. We've already had distributed systems for some time. Certainly they started getting huge when the internet came about and the languages that we've been using to program these systems. And yes, I mean programs. So operations is about programming systems are things like Bash and Puppet and Chef and Ansible and Salt. And all of these are imperative in style. They're very sequential.

00:16:43

Now, as these systems get more complex and more broadly distributed, if we think about the systems programming, what are some of the more modern tools that we can use? Well, at Pivotal, I work on our cloud foundry platform. And so our cloud foundry platform, PAs, cf, PAs, and an underlying system that's underneath the covers called Bosch are different styles. And Kubernetes is something that now has really drawn the attention up around this new style. And we'll see what the style looks like in a moment, but it really is more functional in nature. So if we look at imperative versus functional for systems programming, on the imperative side, we have scripted deployments, very imperative. On the functional side, we have declarative deployments. SSH, we replace that with immutable infrastructure, long running contexts that stick around for a long time that we make changes to are replaced with ephemeral containers.

00:17:54

And finally, middleware that has all of this stuff bundled in it is replaced with this notion of sidecars. So what I wanna do is I wanna study each of these four things in a little bit more detail. And again, the point here is that we cannot reason about all of the details of our complex systems anymore. We have to have software assist us with that. We need a different model for thinking and designing these systems. Alright, so let's start with declarative deployments. imu. So declarative deployments starting from here. We have, um, a whole bunch of nodes out here that are going to get some of our deployments into the way that we do that now with things like Kubernetes and Cloud Foundry is we declare what our application topology is gonna look like. I have for example here declare, uh, declarative manifest that says, Hey, I'm going to have, um, three instances of one microservice, five instances of another microservice and two instances of a third microservice.

00:19:11

I tell the system this is what I want. I don't say deploy the first one on this node and deploy the second one on this node and deploy the third one on this node. Why do I have to decide that? Why can't I just say, here's what I want and some intelligent system makes it so they evenly distribute across my availability zones, they know what those are, let the system do that for me. And then if I've got another workload that's around compliance or auditing, can't I just say, Hey, I've got this compliance need and I need that on every single one of my nodes. Please put it out there. That's what I mean by declarative deployment. Instead of me deciding where I'm gonna deploy things, let a system do that analysis. Now, the way that this works is in Kubernetes, there's a constant control loop.

00:20:05

I joke around that Kubernetes is fundamentally a whole bunch of infinite loops. You declare what you want and there's a whole bunch of intelligent controllers that are constantly comparing what you want to what you got. And that's what that, that's the way that works. So what that means is if I were to lose a node, for example, one of my worker nodes goes away, that intelligent control loop will recognize that there's a difference between what I have asked for and what the actual state of the world is, and it will repair that. That's pretty significant. That's the difference between imperative programming. I have to now go decide, oh, uh, what nodes did I lose? What workloads did I lose? Now I'm gonna go deploy this here and deploy this. There. No, I, my model is here's what I want. Let the software do that work for me.

00:21:05

And of course there's, as Kubernetes, I just said, there's a whole bunch of infinite loops, a whole bunch of different controllers. Now if I take that back to the functional programming model, here's a very simple functional programming model that just sums up the numbers up to some value. N the way that we think about it from a functional perspective is there's a base case, I declare my base case and then I just say, well, if I'm not in my base case, I'm going to break my problem down into, I'm gonna assume that I can get the right answer for some rest of the problem. And then my job is just to put together the start of the problem with the answer from the rest of the problem. If you remember from your computer science education when you took like theory, any kind of theory class, this is the inductive proof.

00:21:58

So there's a little bit of a leap of faith, like I'm gonna assume that the answer comes back right from the rest of this and I'm just going to declare how to combine those answers. Pretty cool stuff. Alright, so now let's move on to the second one, which is immutable infrastructure. Now sure, immutable infrastructure is, we all know this. Pipeline's not humans, but you know what, if we don't change the model that we're thinking in, challenges remain. So that simple pipeline that I just showed in the previous slide kind of took the the general approach that we've always done. Provision a system, configure it, deploy my application, configure it. It's a very imperative way of thinking. Now, some of the problems that remain with this type of approach of just automating what the way that we've been doing things in the past is that it can be slow.

00:22:58

So provisioning even a virtual machine, even with that automation can take 5, 6, 7 minutes. And if you are doing that in A-S-D-L-C, if you're doing it as a part of your, your developers are doing it as a part of the development cycle, waiting five or six minutes to see what the output is from some small change in code is just plain old too long. Or if I am in running in production and I've got some type of an issue, I'm not gonna redeploy, I'm gonna SSH into that box and make a quick change because every moment of downtime is a problem. So we end up with snowflakes. Another thing is that dependencies are very, very complex and those complex dependencies can also result in snowflakes. So if we go back to this picture of the pipeline, which just pipeline automated, took an imperative style automated that we end up with these challenges that we saw.

00:24:03

So let's try to challenge that thinking. Let's look at the first part of this pipeline and change it from that whole provisioning. Provisioning and then, um, doing some configuration. Let's create a platform, a self-service platform that's gonna allow me to just consume when I need to deploy applications. So that's key number one. So we start to build some of our pipelining, we build that into the platform itself. Then the other thing is that if we make that platform a container based platform, containers don't provision in five or six minutes, they provision in milliseconds. So my development life cycle or if I've got a problem in production that I need to alleviate, I can simply deploy a new instance that I can do that in subseconds. So that that first problem of the, of the slowness has really been helped. So we're talking about here a container-based platform.

00:25:11

Now this pipeline is oversimplified. I say deploy and configure. Really what you're doing is a whole bunch of deploy, configure, deploy, configure, deploy, configure, deploy, configure. We've got very complex systems. And so doing all of that series of deployment and configurations is really this configuration nightmare that I talked about. And coordinating all of those pieces together to create my application deployment can be a challenge. So what I wanna do there is I wanna take that complex multi-node dis uh, uh, deployment and deployment topology and I want to take those and create a container or maybe a series of containers that are now described in a helm chart. For those of you who don't know what helm charts are, it is a way of describing a topology of containers that all work together as a cohesive whole. And I want to pipeline those things, but instead of pipelining those things on deployment into my production system, I wanna pipeline those things into immutable artifacts that are gonna be deployed very quickly at the end.

00:26:25

So you'll notice that the final deployment pipeline got super simple and that's because I've effectively shifted left some of the things that used to be in the deployment lifecycle, back into the development lifecycle. Now, what does all of this have to do with imperative versus functional programming? Let's take a look at that. If we go back to this imperative model, what you see here at the bottom is you see the state now watch it. What we see here is as my algorithm is moving, my state is changing. Now I've got my state store, it's mutable state, so it's constantly changing and everything is getting updated. Now how do I know if that those state changes are in fact correct? I have to worry about the correctness of my code, which we already established that sequential code, iterative code mutable state is hard to reason about and it's hard to make sure that we get right, lots of hairy edge cases.

00:27:31

But then all of the complexity in our systems is that there's lots of other influences, influences that can PR influence my program, which is gonna influence the output and other influences that can influence the state directly. On the other hand, on functional systems, the way that this works, and this is the difference between looping and recursion, is that I have my call stack when I do recursion, each one of my recursive calls isn't replacing mutable state, it's actually creating a new frame that captures the information that is required to generate the state. So that call stack, like I said, captures those series of events. The call, the frames on the call stack are immutable. They cannot be changed. So in order for me to get my output, I simply play through the call stack and I get my final state. Now if for some reason I lose my final state, no problem, I can just replay my call stack.

00:28:45

That's really interesting. So if we take a look at that, now your containers, those containers that I am building by shifting left are a little bit like my immutable stack frames and the controllers that I talked about earlier are a little bit like my interpreter. You see the parallels really pretty cool. Now we're seeing this pattern in another place and that is with event logs. So everybody's heard about Kafka, right? And I was at Kafka Summit last week and probably the most in, uh, most common use case that I saw talked about at the Kafka summit was this, I've got a legacy store that is this monolithic thing. I wanna build all these net new applications, but the cadence of evolution on the legacy store is so slow that I cannot get what I need in these microservices that I'm building over here. The way that they're doing things there is they're taking change data capture from the legacy store, putting it in the event store, the event the events in the event store are immutable and sequenced, just like the call stack, immutable and sequenced, that allows us then to take that information and hydrate a whole bunch of independent stores for my microservices.

00:30:11

Pretty cool stuff. Alright, so let's move on to the third thing and I'm gonna speed up a little bit here. And that is, let's talk a little bit more about those ephemeral containers. Now, if we go back to this, the, the, what we've been looking at before, before I had long running state, and on the other hand I had these dis many disposable stack frames. So the stack frames don't write over each other. And so therefore as I play through them, I can dispose of them. Or like in the Kafka case, I don't dispose of them. I keep those things around. Now, let's go back to our picture here of our host, which is, let's say a VM and the container, which is the little dotted line box there. And in the container I have my root file system, runtime layer, application layer, and so on.

00:31:07

Now I'm gonna paint a scenario here. A bad guy comes along and inject some malware into that system and we know that these types of vulnerabilities have caused all sorts of breaches. Now the bad guy goes away. So it's easier to detect, to detect a, um, a, a breach when somebody's in there. But the way malware works is they come in, they inject the thing and then they go away. Now if I've got ephemeral containers and I've got a system and I'm thinking in a model around ephemeral containers, I'm designing my stuff so that I can on a periodic basis just simply get rid of that container and rehydrate it with a immutable new instance of that container. So I've remember I've created those immutable resources in my pipelines and I can just deploy them in milliseconds. And I can even do this at the host level.

00:32:09

What if I replace my hosts on a regular basis and can get rid of that malware? So what I'm suggesting here is that you can repave your environments and this is increasingly a popular thing that folks are using. I can repave the entire environment, um, because I'm thinking about immutable ephemeral containers, and you can do that very often. I have one customer who does this, who re paves his entire environment. That is every single instance of every application is getting refreshed every three days. He does it twice a week and he wants to move to doing it daily. So I'm talking several times a week often.

00:32:59

Alright, so let's move on to the last thing, which is sidecars. So before we talk about the details of sidecars, I wanna talk about personas for a moment. So we've got individuals who are building applications that are going to be, um, used by your customers. So the end user applications, they're responsible for rapid iteration and getting the value out to customers. Now the platform team is providing them the platform that's gonna allow them for that rapid iteration. And that platform team, however, is responsible for, um, things like security and compliance, making sure that the company stays out of negative headlines. So let's keep those two personas in mind as we look through these pictures. So here I have my workloads running in production and I have my auditor or my compliance officer who wants to keep an eye on those types of things. So how will they do this?

00:33:59

Well, again, a system like Kubernetes did something very, very smart. Their smallest unit of deployment is not a container. It's something that they call a pod. And a pod can have multiple containers. What this allows you to do is it allows the app team that's doing the rapid iteration to provide a container with the app and it allows the person who's responsible for compliance to provide a container, a sidecar container that sits right next to it that is concerned with the security and compliance, and those things work together. What that allows us to do then is it allows us to take this picture and attach those sidecars. It's a cross-cutting concern to every single component in there. Now Kubernetes was smart. They did that even more. There's another concept. This, this auditor is also interested in what's going on on the, not only in the, in the containers, but on the machines themselves.

00:35:11

So Kubernetes also has a notion of a demon set and the demon set allows me to inject something else. I'm starting to get the hook, I'm almost done. I promised Gene. Um, it allows me to deploy those. So on this picture, it allows the me as an auditor to make sure that I've got a workload running on each vm. It's about cross-cutting concerns, injecting those cross-cutting concerns. So what we have here is we can inject those cross-cutting concerns both into the platform and into the pipelines that are creating the containers that we deploy. So just to quickly sub it up, if you remember what we had here around systems programming, the parallels are there. We have declarative that was on the programming languages side, immutability, recursive, and we've got aspect oriented programming. Thank you. We cannot <laugh>, gimme, gimme just 50 seconds, 30 more seconds here.

00:36:13

Uh, we've got functional systems programming. I don't wanna leave without saying and I'll skip through this slide. It's all about the toe turn is I do wanna say, encourage your developers to look at functional languages, encourage your platform teams to look at the functional approaches. And finally, what I need help with, and I'll skip through the warning. The warning goes back to what Topo said yesterday. Don't use, um, old patterns and try to automate those. Is are you doing this? I would like to hear stories about who's doing this and also how we can achieve the transition from imperative thinking to functional. Thanks for the extra few minutes.