Submind YouTube summaries
Thumbnail for Event-Driven Evolution with AI as my Partner in Design - Naomi Gotts

Event-Driven Evolution with AI as my Partner in Design - Naomi Gotts

Watch on YouTube

Video summary

Naomi Gotts opens her presentation by contextualizing the evolution of a legacy Laravel monolith at Tillow, a global gift card network that has grown alongside its business over the last decade. While the application carries significant technical debt and operates within a complex financial environment involving buyers, suppliers, and third-party integrations, it remains a critical asset responsible for processing over a billion pounds in sales annually. The core challenge driving this talk is the need to transition from an inadequate relational data model to an event-sourced architecture. This shift is necessary because the current system struggles with mutable history, constrained data structures, and limited traceability as new products like "Choice Plus" introduce complex transaction paths that span different times and actors. To address these architectural challenges, the team embarked on a journey of domain discovery heavily supported by AI, specifically Google's Gemini. Naomi illustrates how AI served as an educational partner, helping engineers grasp complex financial concepts like double-entry accounting, journals, and ledgers through simple queries and scenario-based explanations. The team utilized AI to transcribe meetings with their finance department, summarize comparisons between various event streaming technologies like Kinesis and EventBridge, and even generate example code for experimentation. This approach allowed the engineering team to rapidly acquire the necessary domain knowledge to design events that accurately reflected financial realities, such as ensuring that every money movement event contained both debit and credit legs to maintain accounting integrity without floating-point errors. The technical implementation focused on designing robust event structures and adhering to the transactional outbox pattern within Laravel to ensure data consistency. The team defined specific event types for allocation and settlement, using an "outbox" table to guarantee that database updates and event emissions happen atomically. AI played a crucial role in validating JSON schemas, suggesting naming conventions for event keys, and acting as a consumer to project future states based on event streams. Ultimately, the conclusion is that while AI significantly accelerated learning, evaluation, and coding tasks, it did not replace human judgment. The success of the project relied on continuous human conversations to verify AI-generated insights, solve complex problems, and maintain the craft of software development, proving that AI is a powerful support tool rather than a replacement for critical thinking and communication.
Read the full video transcript
A warm round of applause for Naomi and her talk about event-driven evolution. >> Which hand? >> Thank you very much Dave and it's great to be back here at PHP UK. Uh thanks to all the organizers for once again putting on a great conference and I for one love a an interesting conference venue. And who could have failed to notice that massive piece of Roman wall that's surrounding us today? A true example of modern construction built around but also embracing its legacy. And whilst that Roman war might have a legacy of 1,800 years, today I'm going to talk to you about a Laravel application with a legacy of a mere 10 human years. Although in computer years it's more like 200. So it's sort of a Victorian era infrastructure project. But yes, this Laravel application is a legacy monolith by our definitions. Um, it has evolved with the business that it serves over time. It has its fair share of technical debt. Would we call it award-winning? Well, to coin Gary's phrase, it depends on who you ask. Because whilst this application might not be winning any awards for clean code anytime soon, last year this Laravel application put through the sale of over1 billion pounds worth of gift card sales. So it does depend on who you ask. Welcome then to the real world of successful software development. one of compromise, one of adaptation, and one of evolution. And it and I'm hopeful that some of you here will resonate with this picture because it likely means that you're working for a company that is doing something right. And it also likely means that your job gives you the challenge that is worth getting out of bed in the morning. the type of challenge that puts the word engineering in software development. And today I'm going to talk to you about a few of the challenges that I and the team I work with at Tillow have been facing and tackling over the last year alongside our new partner AI. My name is Naomi and I'm a lead engineer at Tillow, a global gift card network connecting buyers with brands through our gift card API. And this is Anie, our Armatillo mascot. He's very excited to be here as well. Outside of the world of gift cards, I am a big Formula 1 fan. I am a crafter and I am also an adult fan of Lego. So, you feel free to talk to me about any of these things as well. But back to the work stuff. And for the last 5 years, I've been working with the team at Tillow on our core Laravel application. I've helped the product evolve and I've watched the company grow from strength to strength. Throughout that time and actually throughout my entire career, the software development landscape has changed massively. Gone are the days of 20 years ago when I'd be editing a file on a live server in QFTP, hitting the save button, and causing a production white screen of death because I forgot a semicolon. That pace of change has kicked up several gears just in the last year as the AI has taken the software development world by storm and caused more hype than I've ever known anything to in the industry. Navigating that hype, especially when it's all you see on social media, is not easy, particularly when it promises that it's going to change every aspect of the job you have known and love for the last 20 years. So, what does this mean for me? Well, as I've literally just said, change is nothing new. In fact, as the old adage goes, it's the only constant. And AI is just the latest tool that we need to get to grips with. This one does feel a little more fundamental, however, and I will admit I am a cautious adopter. But I am open to seeing how it can improve my workflows and processes. >> Yeah. >> And that's why I'm here today to share some of my real world experiences of my dabbings with AI as I worked with the team at Tillow as we embarked on a journey into the world of event sourcing. So today I'm going to take us through the Tillow model brief introduction so you can get a concept of the some of the challenges we were facing. Then we'll deep dive into events. We'll look at some domain discovery, uh the design of events and also code implementation and I'll finish with some final thoughts. So the Till model uh yeah to model gift at the center at the heart of the Tillow model is the Tillow gift card API. To the left we have our buyers. They integrate with our API. And to the right, we have our suppliers. We integrate as suppliers to obtain the gift cards that the buyers are ordering. And of course, we have multiple integrations to multiple third party suppliers. So this is our this is our basic model of business. It's a financial process and it's our core um critical path. And actually there's two transactions going on here. There's the one on the left between the buyer and there's the one on the right between the supplier. And at this simple stage of model we store one row per end to end transaction. So one row in our sales table would contain the data for both the buyer transaction with Till and Tillow's subsequent transaction with the buyer sorry with the supplier. Now, as I've mentioned, our application has evolved over time and over time we've modified our product offering and one of the things we have introduced more recently is a product called Choice Plus. Now, when a buyer purchases a Choice Plus, we don't actually need to reach out to as suppliers because we issue Choice Plus ourselves. And the choice plus is essentially a link, a URL that the buyer then provides to their recipient who can then take that URL, load it in their browser and redeem to the value of the link for one or more gift cards of their choice. So hopefully from this new picture, you can start to see how maybe we're changing a few things about how our our basic model works here. We've still actually got that one transaction between the buyer and Tillow when they purchase a link, but now we've got end transactions occurring on the till supplier side and not necessarily at the time the buyer is purchasing the link sometime later. So, we've got this other path into our API from the recipient path. So, I'm not going to get into the detail of this, but I'm sure you can imagine that this made the data storage more complex. And over time, what that's left with us with is an inadequate model of our financial business process. Constrained data structures which were hampering some of our internal teams like finance, accounting, etc. a mutable history because of course that sales table's got a status column which can be changed over time and limited traceability between transactions that were occurring. For example, link transactions to do with uh redemption choice plus for example. So what did we want? Well, we wanted the opposite of these things. We wanted a better model of our financial business process. We wanted a flexible data structure. We wanted an immutable history and we wanted full traceability. So what we really really really wanted was events or more specifically event sourcing. The ability to construct the state of your application at any given moment in time from events and the data that they carry. Now, I don't know if how many of you in the room have ventured into the world of event- driven architectures of any kind, but when you first out out on that journey, the first thing you typically do is look at the model that you need to via events from. So, here we've got that um the two journeys of the buyer purchasing a choice plus and a recipient redeeming that link for a gift card brand. And looking at those models we we need to decide we need to identify what's happening. What are the events occurring in the system. So doing that we have a choice plus ordered event where the buyer orders from Till. We have the choice plus issued event where Tillow issues the uh choice plus to the buyer. We then have uh the recipient requesting redemption at which point Tillow needs to reach out to the supplier to order a gift card. The supplier issues the gift card and Hill fulfills that redemption request to the recipient. And this is a great place to start if you're thinking of going on the event driven journey. This is known as a process known as eventtorming. And it's a brilliant um process. It's like brainstorming but with events. And you can do this with both technical and non-technical colleagues where you can draw out what is happening in your system. And it really helps to start defining the events that you're going to need. So I would advise anyone interested to look into event storming um a bit more. But we we we could draw out the events that were occurring in our system. But we needed to learn a hell of a lot more uh on at the outset of our journey. We needed to do some domain discovery and we needed to do this in a couple of ways. We needed to do this first on the from the business domain side. So for us that was the financial world and we also needed to do this from the technical domain side. We needed to learn a lot more about events and event sourcing. And how did we do this? Well, of course, we worked with our teams internally um with our finance team and in and within our own engineering team. But this is where we introduce our new friend Gemini. So Tillow has a uh Google workspace and therefore we our access to Gemini was the um easiest route in I guess to um to use. So we use Gemini significantly through this project and that's what I'll be uh talking about using today. So we're starting off with our domain discovery and our business domain specifically. Where did we start? Well, we started with human conversations because human conversation still matters. Um, but it is quite useful to have AI transcribe them. Actually, my first sort of experience of having AI in the workplace was seeing meeting notes transcribed by and being completely amazed at its ability to um pick up on every little every little sort of thing that we were talking about and then summarize it. So, yeah, AI transcribed meetings very useful. Um but through these meetings we were starting to pick up various terms, terminology, concepts that of course we we had limited time access with our finance team that so we took away took away things that we needed to investigate further things like double entry accounting, the journal, a ledger, cost of sales, all sorts of things. So off the back of these meetings, we then started to explore subjects with with AI. some of the first questions that we asked. Please, can you explain in simple terms what a financial ledger is? Yes, I'm polite to my AI. Um, and then what is a journal and how does it compare to the ledger in a financial system and over time we started to learn things learned quite a lot actually. So I'm going to start with a few things that we learned um and specifically first with the journal. So what is a financial journal? So at the bottom here you can see the super simplified version of our Tillow transactional flow where the buyer is buying a gift card. And what we learned about a journal was that it's a chronological record of every financial transaction that occurs on a system. So in this example of our transactional flow, there's two journal entries. The first one where the buyer purchases from Tillow. So it's my example here is imagine you've got a10 face value gift card. The buyer has a£10% discount so they're paying £9 and till by the way this is not real world would have a 50% has got a 50% discount and so is paying the supplier £5. So that's my example use case here. So in that first journal entry you see that the buyer is um paying Tillow um debiting from their buyer funds £9 into gift card sales of £9. And the second journal entry sees uh tillow incur a cost of goods sold of £5 and a liability to pay the supplier £5. And if we Oh, so you can see that's the first and the second um stage of our transactional flow. Um we might uh just extend that example. So we've now imagine there's that whole process happens twice. So 19th, 20th of February, um the buyer has purchased a gift card yesterday and and one again today. So that's what a financial journal looks like. And part of that financial journal is that every entry in the journal must have a debit and a credit. Well, and here we see the debit of £9 and the credit of £9. And this is so that they don't lose track of any money um through the system. And uh yeah that's the concept of double entry accounting. Next we learned about account types. So you can see three different types of accounts on screen right now. We've got liability, income and expense. Liability and income quite easy to understand from my basic concept of knowledge of my own bank account. I guess debiting and crediting money. Um with a liability in an income account. When you debit money the balance goes down and when you credit money the balance goes up. The challenge comes when you start learning about expense accounts where the reverse is true. Um, but I typically think about it as if you're spending money, then you're debiting money and your expenses have therefore gone up. Um, but yeah, we learned about account types. And then finally, we learned about a ledger and how that is very much like your own bank account. If you log into your online banking and you see maybe you've got one or more accounts there, it will give you the overview of your debits and credits that have occurred over time and your your current available balance. And that's what essentially a financial ledger is. It's a summary of any a given account. We've got two accounts here as examples and the balance of those accounts at any given moment. So what did we learn from all of this? Well, the fundamental learnings we took was that firstly the journal is essentially an event store. Um, it's the chronological storage of every transaction that's occurred over time. And the ledger is a projection. You can produce this output based on the events in your event store. So we started to draw lines between the business domain and the financial world and our event domain and our techn our tech our tech world. So let's now think about that tech world and where and how are we going to store these events. Well, where do we start with this? Well, once again we started with human conversations. Um it's super useful if you are lucky enough to work with a team to talk to that team and see what experience they may have of um working with different um systems in the past. So from those conversations we had um systems such as CFKA, Kinesis, Dynamob, Eventbridge come up and of course once we'd collected those things together we could then explore those things further. We would ask questions such as please can you provide a comparison of Amazon Kinesis data streams and Amazon managed CFKA streaming in 2025. Um and what Gemini was super useful for was producing summaries and comparisons. So something like this. So where we've got Cathfa Kinesis and event bridge compared with various different aspects and um obviously with more detailed uh knowledge and information we were able to ultimately make a decision. Spoiler we went with EventBridge. I will come back to that. But in the meantime we did a lot of experimenting. We experimented with CFKA. We experimented with Kinesis. We experimented with Event Bridge. And Gemini was super useful once again in providing example code that we could use to get Kinesis running locally, send to event bridge, etc., etc. As I said, in the end, this is the the architecture that we ultimately chose. We chose to uh emit events from our Laravel application to AWS event bridge from where it would go into Kinesis Fire Hose and then onto AWS S3 as our event store. And then as an example at the end there we've got uh Snowflake which is a data analysis platform. But today moving forwards from here I'm literally just going to talk about this bit the Laravel application and our emission of events. So sorry for any of you that were hoping I would go that way but unfortunately that's not going to that's not there's not time for that today. So we're just going to stick with the Laravel application and and sending out to EventBridge. So after all of that, we'd learned about our financial domain. We'd learned about our tech domain that we were working with. We now needed to start thinking about our event design. What on earth were these events going to look like? So we needed to think about event structure and we needed to think about event content. Starting off with structure and when you send event payloads into AWS event bridge, the first thing it does is it actually adds an envelope itself. And you can see all the keys that of data that it adds here. But you as the sender have control over four of these keys. You have control over detail type which is essentially the name of your event. The source which is some identifier about where on your application the event has come from a list of AWS resources if if necessary and also the detail which is super key because that's where the bulk that's where your main payload of data um will be stored. So we're now going to focus on that detail what we put inside the detail. So we then devised a tiller envelope and it can comprise of the following keys. So we start with an event ID. This being a unique identifier so that any consumers of the event can know if they've seen this event before. We then have a time stamp. Now it's interesting to note you may have seen in the previous uh slide for the AWS structure that they put a time on the event. That is the time that event hits the AWS event bridge. That is not the time that that event was actually produced. So our time stamp here is to six decimal places of when the event was produced within our system. And this helps with things like ordering if you're using a solution like we are with with event brbridge. The next thing is aggre aggregate ID. Now this is the thing that's going to help us solve our traceability of our connected transactions. So in that example say of a choice plus being redeemed every transaction every event that is fired from our system through that process would carry the same aggregate ID and so if you're working with something like CFKA or Kinesis that has shards or um shards or the other word I can't remember partitions that's it shards and partitions then you can um fire and you can direct any events with the same aggregate ID down the same shard or partition. Um, and then we have a correlation ID. This is much more about observability and a single request response process. So if you're working with uh multiple services for example and we do have a couple of different services that may be used as part of our transactional flow the originating service the one that's hit first can generate a correlation ID that it then passes to the next service and then that passes through the request the whole request life cycle. So you get an observability um trait from that um that is can be useful for um for debugging etc. So then we get to metadata and data and this is where I'm going to focus from here on in metadata data what goes where. So in an event source system such as this how much data should be cons considered environmental business rules versus data that is included as part of an event. Again, Gemini is super useful in summarizing and really driving home the purpose of each of these elements. So, data being the facts, the single what happened, metadata being the context, the who, where, how, why, the contextual information of an event, and then also important excluded. So, things that shouldn't be included in an event. So things like bis uh changing business rules um example how a value is calculated. So now we have the basics of the idea of our event structure. We now need to start thinking about our event content. And to do this we return back to our financial journal and the idea that it itself is a repres good representation of an event store. So we've got two uh pro two entries in our journal here. So let's think about how we can represent those entries as events. So one of the first things we were thinking about was right we got to get this double entry accounting business right otherwise our finance team won't be happy with us. So do we do this? Do we create a a different event for a debit and then a credit? Immediate answer we do definitely do not do this. You do this. You ensure that a money movement event contains both your debit and your credit. Um you also if you're working in a financial system you'll notice here that the amount is in integers. Do not work in floating point numbers. If you if you have done you will know why I am saying this. If you haven't avoid avoid avoid the hell that that can bring. So 900. So we got to this point it's like okay debit and credit but there was yet a one more step of our learning that needed to occur and this was key for our understanding. So what we actually un what we actually found out was that the key principle of double entry accounting is that the debits match the credits and there can actually be multiple debits and or credits in a money movement. So the example on the screen now is an example of something that we have in the in the UK there's a concept of a singlepurpose voucher for a gift card. It's something that can only be used on one particular product when redeemed and is therefore subject to VAT at the point of issuance. So what you've got here is us debiting the buyer funds of by £9 and then two credits. one credit of £750 to Tillow's gift card sales and another credit to an input VAT account which is VAT that's reclaimable um of £150 because that sale is applicable has a VAT application to it. And so what we ended up with in our event content was an array of what we refer to as money movement legs where each leg was either a debit or a credit and all the debits must equal all of the credits. And if you do that you um meet the criteria of double entry accounting. Moving on, another thing Gemini was super useful for was giving it scenarios. We I'm sure you you will understand that I've given you a very basic overview of the till model today. Under the hood, there are all sorts of different scenarios occurring and this is typical of most applications. We've got different stock types. We've got a bulk buy feature. We've got different financial relationships. We've got the cancellation process. We've got different charging mechanisms with suppliers. We've got intercomp payments and we've got international payments. And it was great to be able to give Gemini scenarios of these these examples and for it to produce back to us example events as to well this is how you might represent this this scenario in an event in your event structure. Super useful. Another thing that was very useful was to get Gemini to act as a consumer of your event. So you could ask Gemini to produce a projection based on some example events. Um and this was really helpful so that we could see that what we would what we would kind of envision as maybe an output from our events was actually possible to produce. So here we've got if going back to our example of those two purchases of gift cards, you've got um what happens after each of the four events have passed and what the balance of each of those accounts is at the end of that process. So Gemini can act as a consumer. Very useful. I couldn't put this presentation together without mentioning naming things because you know it's we're we're developers and we like naming things. Um, so here's an example of where I use Gemini to help me name something. Now, we had we ended up with an account node where um here we this is what we started with classification and type. What I wanted was to change the word classification to type because that made the most sense. The account type was income. Um, but that meant I needed to change the existing type key to something else. So please can we redraw our example event and in the account element change the classification key to type and change the existing type key to something that makes good sense. The first thing it came up with was name which I didn't like. So uh is there another word other than name that we could use in the account element key that represents the value of the specific type of account? It came up with code and I was happier with that and we actually did go with code. So yeah, naming things. Finally, the last thing I'm going to mention about content is documentation. So we use JSON schema to document our structures and our content of our events. And um I didn't know anything about JSON schema before starting this pro this project. Um but Gemini taught me about it and it was also super useful in validating the JSON schemas that we produced as well. So now we know what the structure and the content of our events are going to be. It was time to turn our focus to code implementation. And again two lines of thought here. Firstly event types and secondly event emission. So, event types. To explain this, I'm going to take us back to our simple till model of a buyer purchasing a gift card. And I'm going to introduce you to the four account types over on the right hand side here of buyer funds, gift card sales, cost of goods sold, and supplier payable. And there starting balance. So, the only account that's got a balance at the start is the buyer funds. It's got a a balance of 100. And we're going to walk through this process. the buyer purchasing a gift card and we're going to see what happens to the balances of those accounts on the right hand side. So in before I get to that point, I'm just going to say that previously we've talked about there being two events occurring in this flow. Now I'm going to change that and I'm going to say there's actually four and you shall see that as I walk through this. So the first thing that happens is the buyer gives us an indication that they want to buy a gift card. Now, at this point, they haven't got the gift card yet, but they've given us this indication that they want to buy it. So, what we must do is we must debit their buyer funds by £9 to prevent them using that money on anything else. So, they then have an allocated balance of 9 £9 and a available balance of £91. Uh, equally, our gift card sale account has a pending balance of £9. Essentially, it's like a check that hasn't cleared yet. It's it's incoming money that hasn't quite landed yet. So, before we can return the response to the buyer, Tillow needs to obtain the gift card. So, we now need to reach out to the supplier with a supplier purchase allocated event. So, we fire this before we communicate with the third party API. We this is our indication that we we are accepting we're about to incur a cost or expense of £5 and we'll need to be paying the supplier £5. So you can see that both of those cost of goods sold and supplier payable have a pending balance of £5. Remembering that that cost of goods sold is an expense account where the balance goes up when you take when you debit money. Okay. So we now reach out to the supplier and all's gone well and the spy comes back. we can now settle that supplier purchase event. Uh we can settle that supplier purchase. So the available balance of both those cost of goods sold and supplier payable is now five. And the final one we do is the buyer order settled where we uh return the gift card to the buyer. And so our buyer funds no longer has an allocated balance. It just has an available balance of 91. And our gift card sales now has a balance of £9. And so when I talk about event types, what I really mean is the concept of an allocation event and a settlement event. And that's what's that's what we are representing here. So you allocate money, it hasn't landed yet. When you've done the thing that means the the money has landed, you can settle the event. There is one other event type that we also have, which is allocation reversal. I'm not going to get into that today, but as you can probably imagine, we use that when things don't go quite right. and we need to reverse things. So, we're just sticking to the happy path today. But now we've looked at that, I want to take us back to this very first event, the buyer order allocated, the point at which the buyer asks to buy a gift card. Now, what do we do at this point when the buyer asks us? Well, the very first thing we do is ask the question, does the buyer have enough money to do this? Um obviously if they don't then we don't uh we just give them a response in the API saying that to the to that effect. But let's say they do have enough money. So the next thing that we need to do is we need to reduce the buyer's balance their in the database in their buy in their buyer funds. But we also need to send the buyer order allocated event. And we now introduce this um condition that both of these things must be successful or neither of them should happen. Why we say this is we want to ensure transactional consistency within our data. We do not want to fire an event to say that we've allocated this buyer order and then the update to the bio funds table fail. And we don't want the update to the bio funds table to be successful and the sending of the event to fail. We want these two things to be consistent. And so we can't just dispatch this event at the point we change the record for the balance. Even if we do it after commit in a database transaction, we still don't actually know that that event has gone where it needs to go. Um so we can't do that. Instead, therefore, we need to introduce another database table, our events outbox. And this allows us to write our event to that database table within the same database transaction that we update our buyer funds. And then, of course, we can send our event to event bridge from that outbox table. But the fact the point of the matter is we have written that event to the events outbox. So we know it's in it's where it needs to be in order to ultimately be sent to event bridge. And what you're looking at here is the transactional outbox pattern and it's really useful and we have made use of it in our um implementation and it looks a bit like this. simple database transaction, two database updates or an update and a create inside the database transaction. And if either fails, then neither of them are successful. And now we've got our event types and we know the pattern that we need to adhere to, it's time to return to our Laravel application and think about the code where we're going to need to implement our events. So the first thing that we discover in our Laravel codebase is that the code that has the useful data to create the events is in and miles away from the database transaction. So we're going to need to emit the event. Great. Okay. So we're going to need a solution for this. Solution being we need to prepare the event where we have access to the useful data and we need to send the event when we're inside that database transaction. And so we introduced the builder p we made use of the builder pattern. We have a manager class that makes use of in its construct a builder class. And there are two functions that are important here. a prepare event function which is where the manager uses the uh builder to construct the prepared data and then a send event function which is used to be used within that database transaction that is responsible for writing that data to our outbox events table. And we created a facade to um make the use of our manager class slightly easier. And um we can call the prepare event in our code where we've got the useful data and the send event where we need to send it to the outbox from where it can go to event bridge. Now this event bridge code don't take don't go and copy paste this. This is just for example purposes only. Um but essentially it it's a command script that looks very very much like this. What we're doing is we are querying the uh outbox events table, collecting the events we need to send, sending them to event bridge using the AWS PHP SDK, and then once we know they've been successfully sent, we delete them from the database table because we don't want a database table to grow and grow and grow continuous for and forever and ever. And that concludes my section on code implementation which brings me to my final thoughts. So where does AI shine? AI shines in in education. We learned so much from just asking questions of Gemini, getting examples from it, etc. And it helps us with our domain knowledge. No end. AI also shines in evaluation. It can review what you're thinking. It can provide pros and cons to certain solutions. It can give you alternatives when you are stuck and can't think of another option to the one that is the one that's in your mind. It can give you examples. It really helped us when we were doing that investigation experimentation phase with CFKA Kinesis event bridge giving us scripts and it was also really useful in producing example projections and it was helpful with validation as well when we were building our um JSON schemas that was super useful however I can't not mention this I'm always absolutely Right. But um no, it it doesn't get things right every time. Surprise, surprise. Um and you should not lose your ability to think. Super important. And human conversations still matter. Yes, we we leveraged the use of AI in this project, but it helped us. It didn't deliver the project. What glued everything together was those human conversations. They still matter. And so I'm going to leave you with a thought about our craft as software developers. And I mentioned our craft in the abstract for this talk and haven't really mentioned it until now. So I thought I'd better do that before the end. Um, so yeah, our craft as software developers, our craft is about more than writing code, it's about complex problem solving. It's about communication, interpretation, and designing solutions that meet the needs of our users. Our craft relies heavily on our ability to think critically, to question, to reason about things, and to make decisions. In my view, AI is a support for these things, but it is not a replacement. And as we continue to navigate this brave new world of AI world, hyped world of the software development, I for one hope that we do not lose sight of this. Thank you. >> Thank you very much for that excellent talk. And I think the positive at the end cuz some of us might be worried that we're going to lose our jobs, but I think we're not because we still need those skills that you uh um outlined. Um if you do have any questions, we've got time for a couple. Put it in the fleet uh channel uh on Slack. Um I've got one. How long do you think AI like as a rough percentage, how much time do you think it's saved or maybe more efficient? Oh, I say um significantly in the area of developing what our events were going to look like. I'm not sure I could put an exact percentage on it, but a good chunk of time for sure. Yeah. Um yeah, we've got a question. Um did you encounter any push back from the financial department within your company when you began relying on AI to explore your domain? If so, how did you bring them on board with the idea of using AI in this critical business area? >> Interestingly, no. Um, I think Tillow as a business is actually very open to in incorporating AI into our our day-to-day practices. And I would say that we leveraged AI to increase our learning at a faster rate than we would otherwise have been able to do. But we did fact check with our finance team when we had learned things. It wasn't just like, "Oh yeah, we know what a financial ledger is and a journal is now. We'll just carry on." No, it wasn't like that. It was very much like, "So, um, we've learn we've learned these things. Can you verify that what we're thinking is actually correct here?" So, yeah, that was again human conversation super important. >> Brilliant. I mean, they might ask AI as well, but you know, Um, okay. Right. Well, thank you very much for that excellent talk.