Guest: Justin Cormack, former CTO Docker, one of the group behind Unikernels
Watch on YouTube
Listen on Spotify
Listen on Apple Podcasts
Read shownotes & transcript below
Exploring AI-Driven Software Engineering for Truly Difficult Systems with Justin Cormack
Join us as we dive into the fascinating world of AI-assisted software development, Unikernels, and the future of programming languages with Justin Cormack, technical heavyweight, former CTO of Docker, and a leading figure in cloud-native and systems programming.
In this episode we hear about:
Justin's recent experiments with AI-generated code and how it accelerates complex software creation
The concept of unikernels and how they differ from traditional operating systems
Challenges and opportunities in building cloud-native and AI-optimized software systems - good, hard, scaleable software
The role of programming languages like Rust, Zig, and emerging trends in AI-friendly languages
Justin's newsletter
#Nix, #RustLang, #AI
Anne Currie (00:00)
hello and welcome to asynchronous and unreliable, a new weekly podcast where we discuss the most interesting ideas and concepts in tech. I'm your host, Currie co-author of Building Green Software, the Cloud Native Attitude and author of the Science Fiction Panopticon series. And today I'm going to be talking to Justin Cormack, tech heavyweight, former CTO of Docker, who has been doing fascinating and highly ambitious experimentation with AI and AI generated code. And I'm really keen to hear what Justin is up to. So welcome, Justin.
Justin Cormack (00:36)
Nice to be here. Nice to catch up with you as well.
Anne Currie (00:40)
Yeah, it's very nice. So we were just before this talking about the fact that we used to meet at meetups and conferences in London all the time. But we don't so much anymore. I constantly think of a plot that we had 10 years ago, which was that we both agreed that the value of conferences was less about the talks, which you can watch online, and more about the hallway track, the conversations that you had.
Justin Cormack (01:14)
Totally. although it's interesting. I have been to a few conferences recently that don't record the talks, which is an interesting kind of nuance. And I yes, I remember we decided we should have a hallway track-only event, which we should do. I've been wondering about doing another event. I've done two in my life. the first one was Maybe twelve years ago now, I think, or maybe yeah, which was very indirectly how I ended up at Docker in a very complicated and long winded way. sort of traces back to that event. and the second one was a sort of slightly random follow up to that one in Switzerland at the top of a mountain. but I've been wondering about running another event and Anil keeps trying to persuade me I should
Anne Currie (02:12)
this is so interesting. So Anil, you're talking about there is Anil Madhavapeddy who will also be on this podcast as a guest. I met both of you, oddly enough, separately, not together. Although you were working together, you were basically the founding team, or at least the noisy two founders of the Unikernels project, which is, I think, surprisingly, re-relevant again.
Justin Cormack (02:21)
Yes, we can talk about that. I've been thinking about that too recently. To come around to what I've been working on recently, I've been thinking about I mean..., AI kind of started being interesting for coding and it was all very exciting and you could create something in a few minutes. And I thought, well that's all kind of very well, but like these things are kind of small. I mean they're useful and fun and whatever, but like can we actually create more difficult, complex stuff?
And I've really been kind of experimenting with that kind of thing. Because I think like the interesting thing is can we can we build things that took a really, really long time before more quickly because you know there's hard big software in the world. And I know a lot of people, for example, who've had database startups and it takes a decade to build a database startup really, which is a long time. Like if we can accelerate those kinds of things, we can build new software.
And then also just thinking generally about system software, if we can have more of that, then we can do new things. And a lot of the system software we use is quite old now. and you know, you're kind of forced into using things that have been around For a long time, which are great because they're tried and tested, but they also have particular ideas about how the world should work. And they are often written in memory unsafe languages that AI is finding a lot of vulnerabilities in at the moment.
And also one of the things about those large open source projects is they cater to every need because someone comes along and says, I need this. And my experience as an open source project maintainer is that it's really hard to manage projects like that because you don't really know if any of these people are still using those features. You don't know how to test them. You don't know if that use case matters because you don't get any real signal or telemetry out of open source projects.
You just get people along who want to ship features in it. And so you end up with these Projects that have an enormous number of features, which become very hard to maintain.
When I was at Docker, Solomon [ed: Hykes, founder of Docker] ended up deciding that this was so bad that we would have a policy that we would not have any more projects like that. and if you wanted to add features, that would be external to the project and you could maintain it.
And so you would provide much more of a sort of framework, but not actually have all the stuff. It was driven by the experience with Docker Machine in particular that had enormous numbers of drivers to create Docker on all sorts of cloud and local machine kind of software. And like we didn't have a test suite that covered this stuff. And it was like we didn't know if it worked. We couldn't maintain it. And eventually and it was not great software.
And we kind of we built Docker desktop. Partly to because the success rate in install of the Docker Machine based stuff was so low. So we've ended up in the situation where we have these big software projects that are very generalist. and you know, can AI help us build more focused things that solve particular problems but are still have a lot of that complexity and enable us to build new ways of doing things, try new things out that we couldn't before and so yeah, thinking about things like unikernels is kind of part of that.
Anne Currie (06:53)
oddly enough, so you reached out to me on LinkedIn, well, you didn't reach out, you just commented on a post that I did about episode seven of this podcast, which is a chap called Martin Davidson and his experimentation, which is quite interesting. It's but it's quite complementary to your experimentation. It's quite different, but it's complementary to your experimentation, I think.
And when I spoke to him the other week, we were talking about unikernels and that the whole idea of Unikernels the concept was that Unix or Linux does all kinds of things. It has to be incredibly generalist, which means it's got a huge attack surface It's obviously bloated. It's huge, so much slower than it needs to be.
You just pick the bits that you need and not all the bits that you don't need for a particular application? Is that a good description of Unikernels?
Justin Cormack (07:49)
One of the terms is library operating system, which is another way of thinking about it in terms of like with modern software, we use libraries for stuff. We don't just write all the stuff there it is. So where's the library for my network stack? Where's the library for my drivers, you know, and a lot of the unikernel model is really a you know, about taking kind of modern ways of building software in modern programming languages as well.
We did a lot of the unikernel work in OCAML back in the day because it's a modern nice programming language. that confused some people because it has garbage collection and people were like you can't do garbage collection in system software and blah, blah, blah. you know, and now we have other options like Rust, which allow you to not do garbage collection and things like that.
I think there's been a bunch of operating systems written in Rust like Fuchsia at Google and things like that. And but I think yeah, so library components, like I want these pieces, take a library for these, use them, combine them, there's lots of different kinds of complexity in an operating system and different kind of use cases. A lot of the work I remember doing a while back was in the sort of telco adjacent stuff that was in the other one where actually a lot of it was just about moving packets around and you didn't do much work on the packets you try in fact you deliberately try to do as little as possible because that was the only way you could kind of get the performance you needed.
Unikernels are used in telcos a lot for those kinds of applications and just never talked about. Most of the telco companies you speak to have unikernels somewhere in their organization. Some of them have public things about them and most of them don't.
Anne Currie (09:43)
really, that's interesting. really?
Justin Cormack (10:09)
but a lot of the work we were doing looking at application level things, just building applications that actually speak HTTPS and a kind of modern application. Because modern network applications in general, often if you take a stateless network application, for example, I mean they're not that interesting, but they're kind of a good example where you just don't need a lot of operating system to run them. You need a network stack and a TCP stack. And then the HTTPS stack is already in user space anyway. and so you just need network drivers.
And network drivers, I spent a bunch of time hanging out with a bunch of people who were writing them in LuaJit back in the day and like in user space. And writing network drivers for modern hardware is actually not that difficult. you know, they have a very similar structure of ring buffers and you write packets into the ring buffers and then they have various hardware offloads for things if you want or you don't have to use them if you don't want to. and then there's a bunch of configuration, but they're not that complex.
Storage and stateful applications are a bit more complex. file systems are a bit more complex to build and but even then a lot of you can build a lot of kind of deep applications don't use file systems they write database applications often write natively to the block device already. And block devices again are quite simple. but again, file systems are just bits of software. You can write one if you want.
Anne Currie (12:13)
Yeah, it's interesting. so obviously, you were thinking, well, where are we on AI? So you left Docker not that long ago to pursue your own investigation of what's going on?
Justin Cormack (12:30)
Yes, cause I mean you know, I've been at Docker for almost ten years, and ten years seemed a long time. And I think it was kind of interesting. In the last sort of few years at Docker we spent successfully turning Docker into a business, which was great fun. But in a way, like over the last few years, I guess sort of in the pre-Chat GPT era and just coming into that, the ecosystem around Cloud Native was really changing a lot.
I think there'd been such a ridiculous overinvestment boom in that area that there was a bit of a bust going on and a lot of consolidation and companies that were clearly not really profitable as standalone companies. And that was kind of the era the sort of boom era, you kind of realized there was a bit of a sort of hangover from that kind of huge cloud native boom era
that era was great fun. and we built a lot of great software and I think Cloud Native was an amazing thing, as I'm sure you agree that but it kind of felt like it was, you know, that it was really not quite what it was, if you see what I mean.
Anne Currie (14:02)
I did write a book on it. It was just really hard for people to do and the return on it was like 10x. But the investment was enormous and involved you completely re-jigging your whole business and 10x wasn't really enough to justify it for a lot of businesses.
Justin Cormack (14:40)
Yeah, that's an interesting thing. I mean, I remember for years like there was this graph that someone produced of how many of our applications have we containerized at this date versus how many we thought we would have containerized two years earlier. And it consistently showed that this was very painful and slow compared to what people had kind of hoped.
And you know, people have a lot of legacy applications that they have to go through the whole process of I mean, lots of dot net pre core that they were trying to run you have to first port to dot net core so you can run it on Linux. A lot of that infrastructure. And we spent a lot of time at various points at Docker trying to work out how to help people fix those problems and modernize applications more effectively. But it was in the end it was just a kind of long hard slog for people.
Anne Currie (15:53)
Yeah, it is really interesting, isn't it? It is an enormous amount of work to do to go cloud native. And there is a huge reward. But it didn't turn out to be a kind of existential threat not being, it was for some people, was an existential threat, and that's where they had to do it. But for most people, it wasn't. therefore, they didn't.
Justin Cormack (16:21)
Well I think maybe for some, also for some people for some of their applications it was important, for others it wasn't. I think that for example in banking it was an existential threat to get mobile and web banking working. For example. And those things were often cloud native priorities, but then it wasn't necessarily an existential threat to get your legacy back office applications into the cloud. and there was a lot more lift and shift into the cloud.
I mean we had a lot of customers who were really trying to tie moving to the cloud with containerization. but there was an awful lot of cases where it just didn't happen it was just VM in the cloud. Exactly the same VM and that was it. there was a time when Microsoft was when Azure was very early, was going around to customers and saying, We'll just turn your data center into an Azure data center. You'll never know the difference. We'll just move all your workloads into Azure and we'll take over this data center and you'll be in the cloud then. And were they in the cloud? Well, not in a cloud native sense. No, they were paying Microsoft money for what was on prem before and they could say they were in the cloud in some sense, but not in any meaningful way
Anne Currie (17:53)
A new and unbelievably expensive way of being on prem.
Justin Cormack (18:27)
Yeah, I mean they weren't getting any benefit from it. you know, We had these customers who were absolutely insistent, you cannot move to the cloud without doing containers and this is our route and but I don't think it you know I still, it just meant that they didn't do the lift and shift bit, but it didn't make them any faster, really. I mean we didn't start wasting a bit of time doing lift and shift, but Lift and shift wasn't a lot of work. I don't no work, no benefit, I mean
Anne Currie (18:58)
And then actually not just no benefit, the anti benefit. On-prem you have the bizarre counterintuitive benefit of constraints. it's like if you can't have an extra machine, you think of ways of not needing an extra machine. But when you can always have an extra machine, you don't think of ways for not needing an extra machine.
Justin Cormack (19:24)
Yes. Yeah. I yes, I know I've met people whose job was to shut down things that people who've left the company had left running and hadn't been touched for two years after they left and they were gonna shut them down to see if anyone was actually still using these things because there's an awful lot of that stuff. The management layer for what stuff have we actually got? is still hard for a lot of organisations.
Anne Currie (19:59)
It's as we say in building green software, the first stage in building green software is basic operational competence, which is you need to know what's running in your data centers. That could save you money and it's much more secure as well. most companies don't feel too bad if they're not there, because unfortunately, that's most companies.
Justin Cormack (20:27)
Yes. and I mean I think it's an interesting problem. I think part a lot of it is because to really understand what you're running and why, you actually need to have a kind of product model of what everything does. and code has generally been sort of something that sits underneath the product. And I think that while there's a bunch of tools aimed at engineers like Backstage, they should be aimed at the whole organization. And I think AI is really going to make that even worse because people are building more kind of ad hoc tooling into things that again, no one really knows whether it's load bearing and how it relates to other things.
Anne Currie (21:29)
Holly Cummins, who's also on this podcast, always describes this as... I saw an excellent QCon talk from her where she was talking about all the different ways you could try and work out what your zombie servers were that aren't really doing anything or aren't delivering enough value that it's worth having them still operating. And she said, she really came down to in the end, it's the scream test: you turn it off and see if anyone screams. that is really is it. Which does mean you're going to end up with some screaming and no one really wants that.
Justin Cormack (22:06)
the screaming may take a long time if it's something that produces something that's vital for your annual report.
Anne Currie (22:14)
Delayed very big scream.
Justin Cormack (22:16)
Yeah.
Anne Currie (22:20)
Indeed. But so, so it's interesting, we all got a bit burned over cloud and cloud native because we all thought that it was coming really fast, that it was going to replace everything and that everybody was going to go cloud native because it was so good compared to on-prem and then that didn't turn out to be the case.
As it turns out, cloud native could coexist with the old world. Quite happily. 10x is not enough to necessarily justify completely restructuring your entire successful running business. A 10x reduction in your hosting cost or 10x improvement in your performance or resilience or whatever for a lot of business. Some businesses it is existential, some businesses it isn't. But the interesting thing for me about AI is, is it the AI native - you getting AI to write your code. Is that something like cloud native that will coexist with the old world in which humans write the code? What's your current thinking on that?
Justin Cormack (23:30)
I mean I think that I'm not seeing a lot of people who have adopted AI coding who want to go back. you see a few, but I think that even when it's not working very well, they still don't want to go back.
I mean so I think it's it's difficult to see it really coexisting. and I think it's partly because the experience as a developer is so different and it's quite compelling even if it's frustrating at times when things don't work how you want. it
If you remember the early days when it was sort of autocomplete and autocomplete was much less compelling. because it just felt like it was faster. We already had autocomplete and it was just a bit more autocompletey. but I think that the sort of introduction of Claude code and the command line AI and that kind of harness the command line based harness kind of changed things a lot because it It put you in a different context that for most people was different from the IDE that they used to work in. And although there are some people who use Claude code with an IDE, like a lot of people just switched out of being in IDE mode and just use the IDE as a kind of occasional thing, not a permanent thing.
And so it put you in a different context, which I think is very important to kind of change your mental state, is like, okay, this is different. And I think it kind of showed a different kind of way of doing things that was quite exciting and it could just, when it worked especially, it was just amazing. You know, everyone has their sort of first story of their thing that they built that they always wanted that they've never had before.
Anne Currie (26:18)
What was yours?
Justin Cormack (26:23)
I kind of built a few small things, but to be honest, part of the reason I started building larger things was I was like, well, that's all very well, but I need "build small things" to be a kind of path, you know, as a tool or something for building something else that's larger. And so none of them were that exciting. I don't think.
Although actually more recently I, talking kind of unikernally things, I was experimenting with just building a minimalist Linux operating system in Rust and I was annoyed that I got the AI to build this OS and then I wanted to initialize the file system for it to run on, the application to run on. And it decided whether it would have to bring in like makefs.xfs to make the XFS file system.
It's like, I can't seem to work out how to get these dependencies down. Like it's bringing in hundreds of megabytes of dependencies and I was like, this is annoying. So I just spun up another AI agent and said, Can you build makefs.xfs? I want it to be written in Rust, make it exactly the same output as makefs.xfs. use that as a test oracle. Like any size file system, you get exactly the same output. There's a few configuration options, like support the obvious ones and not the obviously legacy ones.
And a couple of hours later I had makefs.xfs in Rust that worked for any size file system. It was bit for bit identical. It did it gradually incrementally. It reversed basically read the docs and the source code for XFS to work out what all the structures on the disk actually are that the thing writes. And filled them in bit by bit and wrote a test suite that parsed them and worked out which ones were different. And then it was actually really nice. It was like Okay, I don't have to add a hundred megabytes of stuff for this. I can run my application on a minimalist file system and an init system that's all one program. so not a unikernel, but a very minimalist user space without any traditional Unix user space at all, just a single, or two init system and the program you want to run and brings up networking, formats the disk, all these things you want to do when you bring up an appliance.
Anne Currie (29:13)
Yeah, blimey. But that's yeah, that kind of ability... that's just utterly revolutionary, isn't it? And that wasn't even the big thing that you decided that you were going to focus on.
Justin Cormack (29:26)
No, I was just looking for something to run. I wrote a post about this a while basically about how to do experiments with AI, particularly in because AI is an amazing experimentation tool. It's like I want to try something out that would have taken me so long that I never would have done it as an experiment. I would have had to commit up front really or feel terrible about wasting all this time.
I spent a bunch of time doing some consulting around embedded Linux systems for edge use cases. and I was kind of interested in like different ways you could build these with different kind of systems. So I built one using Nix. if people don't know what Nix is, it's a declarative effectively programming language for building software that has a Linux distribution and you can use it with any other distribution. everyone used to hate Nix because it was really confusing and complicated and took a long time to learn.
Turns out that AI is very good at writing Nix, likes it because it's easy. I mean I kind of encourage it but it's happy to you know, I kind of slightly encourage it maybe, but usually it does, I can use Nix for this. Because if it's installed, it notices it can use that to install any software it likes using Nix in a reproducible way rather than having to ask you to use sudo to install something up front and it or improvising 'cause it doesn't have the software it needs, which AI also does in weird ways. I had an AI literally writing Python scripts to modify the kernel binary because it didn't have the tools it wanted and I like, Okay, you can do that if you want. I don't mind, whatever. you could have asked, but whatever.
But yeah, so I tried building with Nix and it was because I was kind of interested in how that would that thing I built previously for this with this kind of using a more conventional OS and I built it using Nix and it was nice and it managed to build it. And then I was like but it was still a hundred meg of stuff and I was like, why don't I experiment just building this just from code as well. So I built that as well. It was kind of that's when I built the XFS thing and it was you know, obviously much more there was some functionality that I didn't implement, but generally it did most of what I wanted.
And you could do these experiments on the side while you're doing something else. and if you treat it as an experiment the AI is quite good at like making experiment like decisions of deciding what not to do and just generally not necessarily making everything production quality upfront and things like that.
But you can then basically, I tend to start them with a sort of script of "this is what I'm trying to experiment with", write a plan and then because it's an experiment it changes part of the way through and you just try some different things. But even just watching the AI use some code tells you a lot about how usable the code is and how the system is. Because you want to build something that you could build on in the future. If it gets stuck straight away and can't build anything, then that's clearly not a good design. if it's really slow, and it's spending a lot of time building stuff that takes a long time compared to the actual, you know, AI runtime, then again that tells you like you've got a performance issue that it would help to fix.
Anne Currie (33:59)
You sent me a video to watch in preparation for this podcast of a talk that you've done at I can't remember which conference it was.
Justin Cormack (34:19)
AINativeCon last week.
Anne Currie (34:21)
AINative Con and you've stepped away from small scale experimentation and leapt to the other end of the scale entirely with, "could you re-implement Amazon S3?"
Justin Cormack (34:40)
Yeah. Yeah. I I've always been very fond of S3. I gave a talk at KubeCon a few years ago about why it was my favorite cloud native thing. it was obviously one of the earliest ones. It was the first cloud service I ever used. I think it came out in 2006, it's twenty years old. I think I probably used it in 2008, maybe. as shadow IT because it was very hard to get anything commissioned at the place we were at because it was in the on prem era. and I was told off for creating some S3 buckets and using them for some stuff and it was like, well, okay, but you could have like, actually had a procurement method that would actually let us have an S3 bucket.
so yeah, I've always been very fond of it as a service. It's a very simple thing. Jeff Bezos called it malloc for the internet, which is a lovely kind of idea of like, yeah, you can create bits of stuff that will be stored on the internet. and we kind of forget it's Amazon Web Services, and it was kind of it felt much more web like back then before cloud native became a thing. It was just kind of like these were web services that you could use from your browser and things like that.
So I spent some time looking at the current open source options for object storage. And because MiniIO used to be what everyone used, but they went proprietary last year. and there's a new Rust implementation, Rust-FS, but they had spent two years working on that. It was coming up to their one point release. They've actually started using a lot more AI recently, which is kind of interesting because it's changed a bit. It's actually a pretty much a straight port of MiniIO.
But I thought, well it's my favorite service. I'll use that as a kind of test of like I want to build a big piece of software that's going to be hard. and how hard could it be? I mean in my talk I have a slide which tells you how long study implementations take to implement. The fastest one I know of was the Oracle Cloud implemented it in nine months. But those were people who just come from Amazon and had done the implementation at Amazon and it was way simpler back then as well. So it kind of and I don't know how big the team was, I should find out. But most of the implementations take a few years.
So I thought, well how long could this possibly take me with AI? And I think ever since then I feel I'm halfway through. after the first week, I must be about halfway through now. After the first month it must be about halfway through now. so I kind of feel it was a sort of slightly bigger project than... maybe should have cut it down a bit. I could have done S3 as it was on day one or you know, I mean I guess as it's got 20 years of legacy stuff. at one point I was like, I can see why they're trying to deprecate all this garbage authorization stuff they had originally, because it's really terrible and it's really hard to implement.
Anne Currie (38:47)
I guess you will have learned. This was all a learning exercise. And therefore, I guess it served its purpose as you learned a lot.
Justin Cormack (39:05)
Yeah, totally. I mean I think but one thing that's really interesting about it is that I didn't use any of the existing open source implementations as a reference at all. although I did borrow some of the test suite for Ceph because they have a reasonable test suite which I used as a kind of "okay, this is probably a good model of where to start with some tests". there's some things they thought were worth testing. but the nice thing is you've got this Oracle. You can basically go to S3 and say, what happens when I do X? and get the AI to do that and say, I want it to be the same as this.
So you've got this kind of thing to ground it with. And I think that it's very helpful because there is this whole thing that happens with AI coding. it changes the tests to match what it feels like should be the case, right? And if you've got this grounding, you say, no, you can't change the test, have to pass on AWS. Run it against AWS.
It got a bit more complicated with that than I anticipated because I didn't quite realize all the bits of non-determinism and eventual consistency that are actually in S3, which made things a bit more complicated because for example authorization like they made they made normal get and put strongly consistent eventually which is nice and so that's straightforward but authentication and authorization and stuff are still eventually consistent and so if you change the permissions on something it takes a while before the permission change actually happens.
Anne Currie (40:53)
Ah
Justin Cormack (41:02)
And that's when I kind of discovered that sort of flaky tests and eventual consistency are very confusing for AI. They've heard about it, but sometimes they say, well, Amazon just changed the implementation I've got to change it again from what I did yesterday because it's giving me a different answer now. I must stick to it. You told me I must stick to what Amazon does. I better change it back again. And I was like, No, Amazon has not changed since yesterday.
Anne Currie (41:10)
I hadn't really thought about that. Eventual consistency. sometimes you just back off and wait and then, which is quite a common thing, back off and wait.
Justin Cormack (41:48)
Yeah, but you have to understand which things you have to wait for.
And now the whole of S3 is designed around retry and these eventually consistent bits and things and so mostly the tests now are pretty good for that. Although I started off by making a single host implementation and then the second half of it has been making it a distributed implementation. So now I'm getting a lot more kind of consistency issues on my own code rather than like the Amazon code. And especially as the tests run, I have a lot of very fast tests.
So there's a lot of issues at the moment with I'm trying to get it to understand back pressure and how to not, you know, how to debug the fact it's overloading and lots of things are timing out. and the system's designed to give back pressure, but you have to kind of give back pressure all the way through and in the right places. And right now that's the kind of problem I'm mostly dealing with. This week's task is getting it to understand and measure back pressure in the system so that it can actually do useful things about working out how to not overload the system and not keep failing.
Anne Currie (43:22)
I hadn't thought about that. It was really interesting you said that because those are the kind of things that normally are learned as they evolve. Very few people design that stuff upfront. You won't catch all of it. It's when systems actually run in the field at reasonable scale. then you start to "oh no that area we need to sort out back pressure and things and then we need to do that and then we need to do that". It's part of the learned evolved function of a system. And you're working out how to get the AI to do it very fast. These things took years to... unearth those behaviors and then work out what to do and then try it out and then fix it eventually. It was very slow, wasn't it?
Justin Cormack (44:23)
Yeah, I think in a lot of cases that's true. I mean I think I'm trying to... my kind of version of done is probably slightly different from other people because it's an exercise in well, okay, how are we gonna do this software well? And I'm interested in how do we make good software?
So I've got three machines down there which basically I'm running the test suite on and I managed to make the test suite very fast, which means it's very good at applying a lot of pressure to the system, much more so than anything else that would so there's basically fifteen hundred and thirty three tests that are basically end to end AWS tests. There's another few thousand tests that are kind of more internal tests. But those fifteen hundred tests, I've got it set up with a user exception test harness that just runs them as fast as possible. I mean it's running sixteen tests at a time on the same server, so it takes two hundred and eighty six seconds to run those on a simulated like I think it's a six node cluster on the one machine. like so it's six processes. Well, it's one front end and five or six back end. I just can't remember what on these machines.
So I'm kind of really trying to load it a lot. and then my plan once that's done, the reason I've got three machines to do it on particularly is I can then do cluster failure testing. I've got a programmable power supply so I can turn them off mid run and make sure everything's reliable when one of the hosts goes down unexpectedly. Effectively actually find issues.
My job is really to be a kind of QA engineer in some ways. I mean it's two jobs. One is to spot stupid things it does and say no. or these weird cases where it's decided that AWS is doing different things or but my main thing is to try and find other kinds of errors of various sorts. And testing is obviously an important way of doing it. It doesn't find everything. but my job is to like look at things and think, is there some more testing we should do? Is there something I'm suspicious of? are there things that I feel are not going well?
And a lot of my sort of cycle has been. Okay, things are going quite well. We build a bunch of stuff. And then I'm like, yes, we're getting a lot of issues like this. It's time to go back and rework and work out how to fix that kind of issue. and I think a lot of what people are not doing with AI coding is doing enough refactoring. 'cause I think it's really a convergence process, where you feed back what's wrong and it converges eventually on something that's better. You shouldn't expect to ever get the right code the first time it writes it, one shot. You should always be expecting to rewrite it. Two or three times.
Which is partly why I think also it doesn't make a lot of sense to read the code. Because if you know it's gonna be rewritten, you're just looking for different kinds of errors and issues. and reading the code sometimes helps do that. but not always. I mean, I spend more time reading the internal APIs, for example,'cause that tells you if they make sense, that's kind of good. but I'm looking for particular kinds of failures, particular kinds of problems. you know and the API tells you if it's got the right sort of modularity. but it's a lot of it's about working out the kinds of things that have been going wrong, collecting a bunch of them together and thinking about well and you know, someone's just asking it like, look, we've had all these six errors that are very similar. How would we have caught these earlier? What are we gonna do?
Once I got the multi-host framework built, it was like, we're getting a lot of errors. We're gonna have to stop and fix the errors and work out what's going wrong and have a stabilization period and work out how are we gonna debug this kind of error. and what kind of observability do we need to actually see what's going on so we can actually fix them. And so it's a kind of steering role, you know, kind of understanding what's not working and kind of feeding back into it.
Anne Currie (50:37)
I think what people are saying is we can already see that we're getting AI to create code, and even Rust is a transitional stage at the moment before we just get it to create like a compiler, you know. You don't look at the assembly language anymore, although we used to. And we don't need to look at the code anymore, although we probably will for a while in the same way that we did look at assembly language for a while. And then after a while, maybe there won't be any code at all.
What's your thinking on that?
Justin Cormack (51:16)
I don't know. I mean I have got it to write assembly language and it's quite good at it. but I think that I actually use things like the type system in Rust to avoid a lot of errors. So for example time of check, time of use, top two issues. Like there was a point where for example the authentication flow was very confused and it was definitely checking things twice. And because authorization in AWS is actually eventually consistent, it's actually fine to only do it once. You don't have to worry about it changing later because it's only eventually consistent anyway.
So you want to do it once at entrance, never anymore after that and everything should be pre-authenticated. So basically I got it to have a, is authenticated type that can't be re-authenticated and carries the authentication information that all the later systems, later things that need it or need to know it was authenticated can use.
So you bring that in the type system. And I think there's been a bunch of other cases like that where you can fix bugs by making sure things can only happen once by using types. And I think those kind of things like type systems are useful proofs of that kind of thing. And so I think I actually think that those things are valuable, because otherwise you have to produce a proof for those things separately. The type system is a basic simple correctness proof system that can be validated fast and the best kind that we've got really. And so it would be a lot more work if it just read assembly.
Anne Currie (53:24)
Mm. Mm. Obviously your background is you're very keen on languages and what they achieve like OCaml and the pairing with Unikernels. And it'd be interesting to know whether or not Rust is now the ultimate, effectively the ultimate language. That we'll never develop another one.
But that kind of implies that you're thinking there will probably be another language developed specifically for AI written code as a better way of forcing it away from certain bugs. It may be written by AI.
Justin Cormack (54:20)
Yeah, I wonder about that. And I mean I don't know, I've been thinking about this for a few years while these things evolve.
I mean my first I thought about two years ago, or maybe three, like early on, was, well I'm definitely gonna use something like Rust with AI because I want the type system. Like I want it to do that validation work up front. you know, why would I choose Python, for example, where typing is kind of optional and weaker.
I actually think it's a little different. I think one of the reasons why Rust works quite well is that the training set for Rust actually matches the kind of software I want to write quite well.
And [Rust] hasn't been around so long that there's lots of different versions of it, like with C++. Modern C++ is so different from historic C++ that they're effectively different programming languages. My C++ friends only use subsets [of the language] and it's very strict, but there's all sorts of other things in the language that are terrible and you mustn't use. so the training set is much more confused.
I tried using Zig a bunch a while back. I did it a little bit more recently, but Again, Zig evolved so fast that [the AI] was trying to write two-versions-ago Zig and it just was very confused. And I was like, I'm gonna have to put the Zig instruction manual in the code ref as reference or something probably to make this work. It's a bit better now. but again the training set's smaller.
I do think that the training set does affect the way it tries to write code. Like I wasn't strongly opinionated about which libraries it should use for Rust, but it decided Tokio was the async framework it was going to use because everyone uses it and like I suspect that if I try and force it to use something else, it'll probably get confused
it's very hard. Like the Zig people, for example, are very controlling about memory allocation. It's not a memory safe language exactly, but they're people who want to control every byte of allocation. Rust, nah, you don't control every byte of allocation. You know, it's a pragmatic language. I did tell [the AI] I didn't want to allocate on hot paths and things like that. And it you know, most it you know, and it puts some structure around that, but it mostly does some allocation. It's not very strict.
When I decided to build a hypervisor as well, which I still haven't finished yet but it's going quite well. For that I was thinking maybe I'd try Zig. So I tried it in Zig and Rust, but that was much simpler because basically it's never it's not gonna allocate anyway most of the time because the stuff it does is so simple it doesn't need to and it's not using the standard library so it doesn't have an allocator anyway and things like that. Like if it wants to allocate it has to actually like allocate memory the hard way on the system. Has to create page tables and stuff like that. so that was kind of turned out to be such a different programming environment. It also kind of didn't matter.
but yeah, I think you get a little bit what the language ecosystem uses. and I think that there's a lot of people doing systems programming in Rust now, so it's a reasonably good training set. I think if you wanted to make your own language for AI, you would have to build up a training set. I mean I do know people like Sean who does Pony who is using a language that hasn't got a training set much. Very small compared to other languages and he actually says it's going quite well, surprisingly well. He gives it strong guidelines about how he writes Pony and examples, but has a kind of strong feedback loop about "you write pony like I do because it's my programming language". so I think you can do that.
I don't know at the moment if there's a lot of benefit. I think that we've got quite a large choice of programming languages now. and It's hard to see what kind of problem you would be solving that building a programming language to solve that problem would be worthwhile. But I do think that if you found some...
I mean I think things like the borrow checker in Rust are kind of interesting because it gets on with that kind of structure quite well. It never seems to have problems with linear it does occasionally uses ARC and reference counting for stuff. But again, Rust programmers do that. They're not totally pedantic. As I said, not like the Zig programmers where they just don't like allocating memory at all. so you know, I kind of wonder where the real benefits would be or even I mean but I think it's interesting yeah, as I said it's a question I've been thinking about a lot. It's an interesting question.
What could you do? My thought is still that you could make it even harder to program and have more types. you know, there's a whole bunch of other type system research that would, you know, that's in niche languages like Idris and things that maybe that would benefit AI too. but yeah my guess is it's more about types and structure than anything. And probably removing things that you don't want. because backwards compatibility is less of an issue.
Anne Currie (1:02:03)
So we've now that that is unbelievably interesting. And that's quite a good, almost a cliffhanger. What is going to happen? Well, don't know. everything at the moment in the tech industry is a cliffhanger. We have no idea what's going to happen. But we have now talked for over an hour and I think my brain is pretty well I've run up against the end of my context window.
Justin Cormack (1:02:17)
Yes.
Anne Currie (1:02:27)
But I'm really hoping that you can be enticed to come back again because you haven't reached a conclusion, you're generating ongoing conclusions
Justin Cormack (1:02:43)
Yeah, I mean I like I've found out that you can get to four hundred thousand lines of code and a complex problem and it hasn't all gone horribly wrong yet and I kind of still feel I mean, I think I now feel I'm more than halfway through. but you know, I just kind of feel I know how to do this.
I'm really interested in like, well, how much of what I've been doing very intentionally by hand I could automate. because at the moment I've been making sure I understand everything that goes wrong because this is an experiment that I need to know the answers to rather than like...#
I've been really interested in people who are doing heavily automated flows and what they've been doing and it's very enticing to say, I could have built this by just pressing a button and but there's a few things that I think are really interesting. one is where things go wrong, particularly around things like security and architecture that are hard to write tests for. you know, that we don't have tests for architecture, or and we don't really have tests for security, so you have to find those things by other means.
Another one, so a lot of them are very successful on the happy path and not so successful on the non happy paths, and how do you test non happy paths effectively?
and I think a lot of them like you could you end up with situations where it sort of superficially matches the API you're trying to copy, but in practice the implementation underneath is really kind of stupid and doesn't really work and is like, well, it looks like this, but underneath we're also doing this and like we're doing inconsistent things for the same thing and But on the other hand, the systems are quite and the other thing is like as we were saying earlier, like you can't come up with all the architecture for a system like this up front and know all the problems up front. It's just like it's too complex and big. You kind of you know, I went into this knowing that it was buildable because there are existing examples of it having been built before. So I didn't have to know that I didn't know I knew I wouldn't have to backtrack on like the entire architecture of the problem. Like it could be built, but on the other hand, I didn't know the architecture I chose was buildable, really. and but you know there's clearly like it's clearly I couldn't have I couldn't have specified this up front because I didn't know the things to specify up front. So I couldn't really just press a button and build it. I still need some human in the loop to make to steer it somehow.
Anne Currie (1:05:45)
Yeah.
Justin Cormack (1:05:52)
But I could definitely have I know I could have less because I've been literally watching pretty much everything it says to catch the stupid bits, and most of that's a waste of time because most of the time it's fine. it's just I don't know what all the stupid bits are going to be, and they're different every time, so it's hard to know. Like you could easily miss them.
Anne Currie (1:06:09)
So that has been a really interesting discussion. The good thing about doing these podcasts is I listen to them like 20 times in order to do the editing of things and at the end, I do know them quite well. Whereas even just reading, it's a different experience even just to reading the thing. But yes, I would say thank you very much.
Justin Cormack (1:06:34)
Yeah, well.
Anne Currie (1:06:48)
I will have a think about this. I'll probably do another podcast in which I discuss what you've just said with somebody else because it's very interesting. Probably Jon my husband, who you've met many years ago. don't know if you remember. And we'll ponder on all of this. And then hopefully I'll be able to entice you back on to talk about what the next thing you're doing on how, you know, the next half, the final half.
Justin Cormack (1:07:14)
Yeah.
Anne Currie (1:07:21)
Yeah, so thank you very much and thank you very much to all our listeners. And hopefully I will and hopefully Justin also will catch you on a future episode of asynchronous and unreliable. Thank you very much indeed and speak to you again soon.