Transcript

Elena van Engelen: Is serverless secretly locking us in? A lot of developers and thought leaders believe that's so. This is a really good question nowadays with intercontinental tensions and everything, so it's really relevant right now. What if you could use architecture to help you keep your business logic cloud agnostic? That's what we're going to look at today. We're going to look at some building blocks that can help us keep our business logic cloud agnostic while we're still using the serverless building blocks on different cloud providers. We're going to look at the Spring Cloud Function. Has anybody used Spring here? Clean architecture. I guess a lot of people heard of that? We're going to use some Gradle modules. This is maybe more specific. We're going to use these building blocks to lead ourselves to the key takeaway, it's a framework for cloud-agnostic business logic.

I'm Elena van Engelen. I'm a Senior Software Engineer specializing in Kotlin and cloud-native solutions. I currently work as a lead engineer at AZL. That's the life and pensions part of the NN Group. I'm also an AWS Community Builder in serverless category, an author on "Kotlin Crash Course" book, and a blogger on Kotlin and cloud topics.

Serverless and Function as a Service (FaaS)

Let's crack on with serverless. What is serverless? Have you used serverless? Who has used serverless? It's not like we don't have any servers. We do have servers. We just don't have to manage the infrastructure. We don't have to scan our containers for vulnerabilities. We don't have to patch our operating system. We don't have to worry about the hardware. It makes our lives a bit easier. It's resources on as-used basis. We scale automatically and we're triggered by events. Let's just compare a little bit with container-based apps. In a container-based app, you might have a microservice or you might have a monolith or whatever. You have a lot of business logic in one thing. If you start scaling, so you need to scale because you have a lot of requests coming. You scale everything. You're going to scale everything. When you have Functions as a Service, they're very simple.

A function has an input and an output, so it's got a lot less responsibilities. You should have one responsibility, really. Your microservice or your monolith or your product will be built with multiple functions. When your events come in, only some or one of your functions need to scale. Not all of them. If you have some background jobs, or you're handling events like messaging or you're handling HTTP events, if one of these get a lot of requests, only they have to scale. You're a lot more resource efficient using serverless. Let's look at some use cases you might use serverless in. These are really common use cases. When I say REST APIs, you're probably thinking cold start. The really big cloud providers like AWS and Azure already mitigated cold start. You can mitigate it and you can still use REST APIs. You just need to make sure you take the cold start into account.

For example, AWS has SnapStart. If you use that with priming on a JVM, you can actually eliminate the cold start and not notice it even on p99. On Azure, you can use Elastic Premium. It's not free, but it will mitigate your cold start. IoT event processing, this is a really good use case. I actually worked at a company called PostNL. It's the biggest parcel delivery company in the Netherlands. They use serverless AWS for everything there. They had like 800 million events per day and they were handling it with serverless. It works really well with IoT. Data transformation, clickstreams, scheduled tasks. If you have a scheduled task, you don't want to have container, keep waiting all day to run it once or twice a day. These are also good use cases if you don't have very long-running scheduled tasks. Basically, serverless can be covering all of those use cases.

Spring Cloud Function

We said that Function as a Service makes our life easier. We also asked, what about portability? Let's look at how Spring Cloud Function, clean architecture, and Gradle modules can help us keep our business logic cloud agnostic. Spring Cloud Function in a nutshell. As I saw only half of you use Spring, so, basically, Spring is like a framework that allows you to use in version of control. It's a very popular framework for JVM languages and also can be used in .NET. I think other languages have got similar frameworks for dependency injection. Spring Cloud Function basically allows us to run a Spring app in Function as a Service. That's what it allows you to do. Therefore, you can use your Spring features in your Function as a Service. Your favorite Spring features, dependency injection and auto-configuration, anything that you like. It's got a really big ecosystem. It's adaptable to the environment.

You can run locally. You can run on AWS Lambda, Azure Functions. They have more adapters for other clouds. You could even write your own adapter if your cloud's not supported. Basically, to run your Spring Boot app on a Function as a Service, you just need the Spring Cloud adapter. Let's just jump into the code immediately to see how that's going to look. Because Spring sells it as like, we are platform independent. Actually, if you start writing the code and you're trying to deploy it to cloud providers, you will see that in many cases, you still have to write cloud-specific code. First, we're going to use the cloud adapter. This is actually cloud-specific dependency, which we wouldn't want to deploy on different clouds, which we only want to deploy this in Azure. This is in Azure. We're going to write a function for Azure, include the Spring Cloud adapter.

Then we need to create a function entry point. This is like a Hello World example. This will be an HTTP trigger. It has a FunctionName. Then we define httpTrigger, which will take a POST on an endpoint docs flow. We will add some basic security. This is a demo, so we won't worry about too much security. Let's just add the basic security. That's an API key, which we will be using for security. This is how the function looks like for Azure.

In order to run this Hello World example, we actually need to deploy it, of course. We're going to use CDK. I'm using Terraform CDK because I'm deploying to multiple clouds. Who has used Terraform? It's Infrastructure as Code. A lot less people have used CDK, that's basically using a programming language to generate your Terraform files, and then you can deploy. Then you use your own language to do that. For Azure Functions, all we need to do is specify a function app where our function will be running. There we have to specify the MAIN_CLASS. This is the MAIN_CLASS of our Spring app. That's the only thing we need to do, and it will work. The Hello World is already running in the cloud. I'll show you, because we don't want to be doing Hello World right now. Anyone can do Hello World. AWS, how does that look?

First, we need to include our dependencies. This is AWS-specific Spring Cloud Function adapter. Again, AWS-specific. We need to include that in our application. Then we have our code to execute when the trigger fires, the HTTP trigger. Where is our HTTP trigger? It's not in the code. It's different. For AWS, we implement our trigger, and that will be using the AWS-specific request and response from the SDK. The trigger is in the Infrastructure as Code. That's different from Azure. Let's just quickly look at the name of the function, uploadDocument. We will need it in a minute. When we go to the Infrastructure as Code for AWS, first, we need to define our Lambda. This is where our code will be running. In order to configure our Spring Cloud Function, we need to specify the name of the function, Spring_Cloud_Function_Definition. That was the upload document name of our function that we just saw.

Then with MAIN_CLASS, again, we need to specify the MAIN_CLASS of our Spring app. We also need to specify the handler. That's what AWS Lambda needs to know what to call when it gets an event. That's actually a class within the cloud adapter, which you need to specify. Once that's done, you need to specify the trigger. We don't have the trigger yet. The trigger is our DocsFlow endpoint. That's going to be our API gateway specification. DocsFlow, we want to go to DocsFlow endpoint. We want to accept both requests. We want to have an API key as well for some basic security. This will be the same as Azure. You can see that the definition is different to actually define your trigger and the entry point. Those things should be kept separate from your business logic.

As I said, we're not going to do a Hello World. That's just boring to do that. What I'm going to do is going to show quickly. We've got two Hello Worlds running. This is the AWS one. I'm showing that I'm pointing it to AWS DocsFlow endpoint. This is running a Hello World, not doing anything, because later on, I'm going to plug in the business logic into those endpoints. Instead of having Hello World, let's go to Azure. Again, the same. Nothing's going on there. This is Azure Function. We're just doing a POST request of nothing. We're not actually posting any information in there, because it's not doing anything. We haven't plugged anything in. That's basically Hello World.

What are we going to build? I'm going to go back to my experiences writing a book. Every time I wrote a chapter, once I finished it, it had to be reviewed. I had to send it via email and have a special name for the chapter so they knew which stage of the reviewing it was on. Then I would send that email with the chapter to the reviewer. First, it would be the editorial review. Then they will send me comments, fix that. Send for technical review. They will do the technical review. Then, again, the chapter name will change because they want to know in which stage that's in. Then it will go to the final editorial review. If later on, you think, actually, I could add this to the chapter that has already been final. Then you go into this exception scenario where it has to be reviewed again.

It's quite really manual. Let's just modernize it a little bit and add a bit of business logic so we can do it automatically. What we're going to do is we're going to use Azure and AWS. We're going to deploy our business logic to both clouds. They also will upload the document. I'm not doing the graphical user interface, so I'll just use Postman to upload. We'll upload a document to the API endpoint. In Azure, it will be Azure Functions. This will validate with generic business logic for this publisher that my chapter meets the basic requirements. Then if my chapter meets the requirements, it could be like image quality and number of words or other. It will save it to storage. In Azure, it will be Blob storage. In AWS, it will be S3. Once my document has passed the validation and been saved, I actually want to do an automatic review.

Let's say it could be like some AI model specific to that publisher that will do the review, some other business logic. These kinds of things will be cloud agnostic. Those need to be deployed on Function as a Service, which will react to the document being placed into the storage. That would actually generate an email with a secure link and go to the human reviewer that can do further reviewing. This is what we're going to do. It feels like a real application. You can see I'm just using the real cloud services. I'm not avoiding using any cloud services, even though I want to be portable. I'm using Azure Functions. I'm using Blob storage. I'm using Azure Communication Services for the email. In case of AWS, I'm using API Gateway, Lambda, S3, and SES, Simple Email Service.

Clean Architecture for Serverless

How are we going to do that? We're going to use a clean architecture for serverless. It's actually a simplified version of clean architecture. We don't need so many layers. That's because this is not your typical container-based app with a lot of responsibilities. It's like a function that's got one responsibility. You don't need too complex a layering. You could use a simplified layering. You have a domain layer. That will have your domain logic, your domain objects, basic domain object validation, for example. Then you have your application layer, which will have your use cases, business logic, your interfaces. Then you will have the infrastructure. That's where you put your cloud-specific code. I believe that kind of boilerplate code eventually would probably be generated by AI. Things like saving to Blob store, saving to S3 code. That code connecting you and your business logic to the cloud, keeping that separate, and just putting that in a separate layer.

Let's just have a look at some real-world examples. We're looking at the pension sector where I'm working. It's not boring. It sounds boring, pension. It's not. You have a participant in a pension fund. You have participant, pension fund. That's two domain objects. You have life events. Why do we need life events? A lot of countries actually have rules on life events, which will affect your pension. Let's look at the Netherlands. If you get married, we need to know about that. That event has to come in, and we have to register it. That's because if you eventually get divorced, your partner might walk away with some of your pension, and they will become a new participant. We will have to process that automatically. We need to know about that. Another event, when you die, we need to know about that because there are some beneficiaries of your pension.

That's basically your kids and your partner. They have a claim on your pension. They will become participants. Also, your ex from 20 years ago, they can claim the pension for the time that they were together with you 20 years ago. It's really complex. These business rules are complex. If I knew about that, I might have thought twice about getting married in the Netherlands. You don't want to keep these business rules attached to your cloud. This is really complex. You want to keep it separate so that you're more flexible and you give your application a longer lifetime. If we look at the application we're going to build now, it's a lot simpler, of course. In a domain layer, we will just put the document metadata, the document that we're uploading. We want to know something about that. In the application, we have two services. One will be validating the document and the other will be reviewing the document, and actually also sending email. It's two responsibilities. Yes, so it will be reviewing the document and sending that as an email to the reviewer.

Clean Architecture - With Gradle Modules

This is how it's going to look in the Gradle modules. You have this domain and application modules. They don't have any cloud knowledge. They don't have any dependencies on cloud. They know nothing about the cloud. With Gradle, we can enforce that and make sure the code won't compile if you try to access any infrastructure code or any cloud-specific code. Then you have a module with each cloud. You have AWS or you have Azure. When we package this to deploy to the cloud, we only package the infrastructure code that we need. There won't be any Azure code in our AWS package or AWS code in our Azure package. Then I also have a CDK. CDK is not actually being deployed because this is just description. This is just a configuration of your infrastructure. This is going to be used in the pipeline to actually deploy your infrastructure.

It's not packaged in your deployment package, but it's just used for specification of your infrastructure. Again, with the Azure. This is how this looks in Gradle because not everybody used it. For example, in the settings.gradle, you can define your modules. Then, in a specific module, you can say what is your dependency. For example, in the application module, I have a dependency on domain. Application knows about domain, but it doesn't know anything about infrastructure. It's like an inward dependency. Domain knows about nothing. Application knows about domain. Infrastructure knows about both application and domain. It won't compile if we do the other way around. This is what we're going to do, put the same business logic. Then we will seamlessly connect our business logic to the cloud using the dependency injection at one time to actually call the actual specific cloud components.

Demo

Let me just go to the code. We're going to do some coding. Really quickly to show you here, we have the application layer. That's the business logic. This is domain logic on my right side. This is the infrastructure. Basically, what I want to do now, I want to connect my business logic into the infrastructure. Infrastructure has the entry points for my function. Before I go in, I'll just go back quickly to the solution design. I can just remind you what we're doing just a little bit. What we're going to do now, we're going to implement the business logic injected into the function that will receive the document and the function that will review the document. The same with AWS Lambda. The same business logic will go for receiving documents and validating and actually reviewing the document. Let's start with Azure. First, I'm going to open the class and then I will close that window so you can actually read the code.

I think it's readable. This is a container for my two functions. One function is UploadDocument, we're going to start with that. When you upload the document, we want to validate it, and save it to the storage. Then after it's saved to storage, we want to review it. What I'm going to do is inject those services. Thank you, AI. Once I've injected the services, I actually want to use them, and replace my Hello World logic with the actual calls. This will actually receive the document and validate it. If it's valid, save it to the store. Then I want to go to the part where I'm actually listening to Blob storage. If there's a document placed, I want to review it. I will replace this Hello World logic to actually call the business logic from application layer. This will review the document and actually send an email.

It's actually doing two things. Reviewing the document and sending email. I've done the Azure Function. Let's do AWS. We'll do exactly the same. Just inject the entry point of our AWS Lambda with the business logic. Very similar. Just let's inject. That's not what I want. AI is not always doing what I want. Once I've injected the business logic, I can actually call that from my entry points. UploadDocument will be called. For the HTTP request, I will be submitting the document. We'll replace the Hello World, and the second function, processDocument. When I have an S3 event, when the document is saved, I want to replace my Hello World with a reviewAndNotifyDocument. We've injected our business logic into the cloud entry points. Now what we want to do is inject our business logic with interfaces, which will connect it to the cloud code without it knowing about it or actually having any dependencies in those modules. That's the last part, what we're going to do. Then we're going to deploy.

We're going back to our application. This is the business logic that we were just injecting. Here we have a couple of interfaces. That's not really a new concept. We have a couple of interfaces. One will allow us to send an email and it will just connect us to the actual implementation. I can see here, I have the two implementations in each infrastructure module. AWS will have the SES email sender and Azure will have ACS email sender. The business logic doesn't know that, of course. Exactly the same with object storage. One is talking to S3, the other to the Blob store. What we're going to do is we're going to go into our business logic. First, the review. Let's just go so that you can see the code. Here we have this DocsFlow request handler. Once I submit the document, it will validate it and save to the storage.

Let's just inject that with object storage. Here we have some validation logic, which is portable. It's just returning true. I'm not actually doing any business logic here because it's just for the demo. It will validate the document, which will return true. It will be always validating, and then it will save. What we want to do here is actually save to the object storage. We're saving to the object storage. We're saving the document. Let's just get rid of the TODO line. That's it for the first service. It will just validate and save. Then, let's go to the second business logic service. Let me open it. This one will do two things. What it will do is it will basically review the document. That could be AI or whatever, your business logic. It then will generate a secure URL to your document, and it will send an email to the actual reviewer.

I'll get rid of that name. We've got the two services that we're actually injecting our business logic. For the secure link, we can call our generic object storage. We don't know which cloud we're calling, so object storage. We just want to generate a secure URI for our blobId. This will have the URI for the reviewer, so they can actually click on the document. This is basically my complex business logic for review. It's actually just a random string at the moment. I'm not plugging in any AI at the moment. You could have all sorts of business logic in there. Once the review has taken place, we can send an email using the notification API. Send email with a review, and review is containing the secure URL. Basically, very simple example. We've done all of that, but before we deploy, let's just build it because what can possibly go wrong when you deploy into two clouds?

Let's just go into the console. I'm just going to build it. Just make sure that I'm green before I do any commit. What I'm going to do now, I'm going to commit to my Git repository, and there I have two pipelines. One will deploy to Azure and one will deploy to AWS. We're ok. This will be committing. Let's just get rid of that. We actually changed four classes. The two function classes specific to AWS and Azure to plug in the business logic, and then we changed the business logic to actually use the interfaces to the cloud-specific things. Now that we're pushed, what should happen is that we should get some pipelines going. Let's see how that's working. We have two pipelines, one's going to AWS, one's going to Azure.

Deployment - Terraform CDK

While that's going, we'll go back and just look a little bit at how we are deploying. Terraform CDK. Not everybody is a big fan of Terraform, I know. There are advantages of Terraform and one of them is that you can actually do deployments to multiple clouds and you actually speak the same lingo. It is different dialect because when you deploy to AWS, you're using AWS resources, and when you deploy into Azure, you're using Azure resources. It's not like it's exactly the same code, but it's still the same concepts. Because you're using CDK, you're actually using your own programming language, which really helps bring ops into dev, so DevOps. You have developers doing it, it's much easier than learning this tf Terraform files. Multiple cloud compatibility, that's coming from the Terraform. Reusability, you can reuse your Terraform module. If I wrote Terraform module in a tf file, you can reuse it in your CDK, or I wrote it in .NET, you can still reuse it because it generates basically Terraform files.

Predictable changes, so if I change my infrastructure, I can see what's going to change in the cloud. How does that look? If I created new Infrastructure as Code, what I need to do is I need to do a cdktf get, it will get all the dependencies. When I do a synth, it will actually generate Terraform files. This is very slow, so only do that when you change your Infrastructure as Code. In your pipeline, only do that when you change Infrastructure as Code, otherwise don't run that because you only need to deploy, like if you are updating your software only and not the infrastructure. You can do just a Terraform plan and apply and it will just upload the new software to your functions. This is a lot faster.

Demo

Let's have a look at our pipeline. Normally one of them completes by now. My AWS has completed, so what we can do is we can start by looking at the AWS one, so let's just do that. Actually, before I go in there, let's just have a look in my S3, I don't have anything, so let's just see. In my S3 I have nothing, so it's nothing saved yet, I haven't submitted any documents. Let's just go into Azure as well, so Air Blob storage also has nothing there. Now what I'm going to do is I'm going to go to my Postman. I think if I do AI in the next year, I will create a frontend with AI. I'm not good at frontends, but AI is different. Here we had this Hello World, so now we're going to go to AWS because it was first. I've clicked on my AWS, this is pointing at my AWS.

It was Hello World as we saw previously, so what we're going to do is we're going to upload a file to review. I'm going to upload chapter 13 that's actually talking about the event-driven serverless on AWS. We're going to review that, so let's just submit this document and see what happens. What should happen, it should review the document and then send me an email with the review and with a secure link. If I click on the link, I should be able to download the chapter and see any review comments. I can see that it's completed, and so there it's got actually some login information that has saved something. That's good. Let's first look at our browser, because then we should be able to see in our S3 that the document has landed. That's it, that's the document. We should be able to see an email.

Please ignore all my other emails. This is the email. It's giving me a compliment. That's good. It says that it flows very well. Then I will click on the document and it should download the chapter 13. If I open that, I will see the chapter 13, so that works. Now what we're going to do is we're going to look at Azure because it's doing exactly the same. Let's see if it's actually deployed because Azure takes a little bit longer with deployment. Let's wait for Azure a little bit. I have to wait for Azure to deploy my app before I show the Azure part.

What I can also do is show you the pipeline. Let's go to IntelliJ. I'm using GitHub Actions to deploy. Nothing complex. If I look at the deployment of my AWS, so all I do is basically, I build the package, and this package will be uploaded to the S3 bucket. Then, because I want to deploy it, I will actually deploy it. Here I will be putting it to a S3 bucket, and then here I'm doing a deploy with Terraform. It's very similar to Azure. In Azure, I will just be uploading to a Blob storage, and then I will be using terraform apply to deploy any changes, what we're just doing right now. Really quickly to show where the CDK is. This is the CDK with the Infrastructure as Code. For example, AWS, it's very similar. I don't know who's used AWS CDK, the native one. It's similar to that, but it's more verbose.

You specify, for example, your permissions when you need to connect. IAM permissions if you want to connect from your AWS Lambda to S3, for example, those kinds of permissions you have to specify here, and then API gateway. Very similar, but more verbose. If I'm only on one cloud, I prefer to use the native one, so the actual AWS CDK. If you want to deploy to multiple clouds, this is quite handy to just have the same language to this. For example, this Lambda permission for the API gateway, it's how it looks like. It's like a builder with actual programming language code.

Let's go back. Azure has finished. Now we can actually do the demo of Azure. Let's go to Postman and go to my Azure Postman collection. It was Hello World. We're pointing at Azure now. What we're going to do is we're going to upload the document. Let's just pick a different chapter. It's going to be chapter 8 about functional programming. Let's have it review the document. It's using the same business logic. Because we are actually doing a random string, it usually picks a different review. It's finished now. If I scroll a little bit like this, you can see that it's saving to Blob store. What we can do is we can go into our Blob store, which was empty. If we refresh, we can see our document there. We should see the email arriving as well. We had our email, about 80% was an email, and this is the Azure. It's got a different review. It says that even AI stopped reading halfway through and needed a coffee break. It didn't like it. Let's improve our document. We click on the document, we can download it. It is chapter 8, so it works.

Key Takeaways

We did the demo. We can go to the final part. Let me just go to the browser. The key takeaways are, if you separate your business logic, you can achieve meaningful portability. You can port your business logic to different clouds. It is really so simple. All of those concepts are not new, but this is actually applied to actually being portable. When companies say we don't want to use serverless because it's then tying us up to the cloud, that's not necessarily true. If I'm in a container and I'm calling S3, I'm still connected to the cloud. I still should be separate. It's very similar problems with the container. Spring Cloud Function will allow us to do dependency injection at runtime. You have other frameworks that do dependency injection. You also have frameworks that do it at compile time. In your other language that you want to use, you probably have a framework like that.

Gradle modules allows us to enforce the separation between the layers. This really helps us to prevent developers from actually abusing the architecture and not following the guidelines. Just because you have time pressure, you have to do it quickly, you have to develop quickly. If you don't really enforce it, then I'm pretty sure it's going to go wrong over time. Kotlin, you don't have to use it, but it does help, because basically when I run in the cloud, I'm not dependent on the JVM because Kotlin can target JVM from 8. That means that when AWS went to JVM or Java 21, Azure was behind. If you were already on 21, you would be having trouble migrating. With Kotlin, I just can use the latest version. I don't care what JVM it's on. That's helping. Terraform CDK also helps you because you're speaking the same language, even though it's different words. Still, it helps for portability.

Resources

I have a Medium blog that talks about the same thing. I've got also another example that does it. If you want to see the GitHub of different examples and you want to see the Medium blog, it's an NN Tech blog, please scan the QR Code. This is my website with some links to my social media, elenavanengelenmaslova.github.io.

Questions and Answers

Participant 1: You have chosen a technical use case and not a domain one, uploading to an object storage. Shouldn't uploading to an object storage be also agnostic?

Elena van Engelen: Basically, it's just upload to storage. It doesn't have to say object storage. It's upload to storage. You don't know which storage, could be like a database. It doesn't have to be S3.

Participant 1: Yes, but then shouldn't the abstraction be on the upload. Then within your business code, you don't know whether it's an Azure Blob storage or an Amazon S3. Because basically S3 is also an API. I think it may work also with Azure Blob storage.

Elena van Engelen: You mean the naming of the function?

Participant 1: No, when do we do abstractions? Technical abstractions from domain logic.

Elena van Engelen: You could just say save. I think I had save there. Maybe the name of the interface might have been different. Basically, it's save. You get an object, like you get a document, and you want to store it somewhere. You could just say store, storage. Or you can say, save, like persistence. You can call it persistence.

Participant 1: Exactly, without knowing on which cloud.

Elena van Engelen: Without knowing which cloud or which database. I could be saving it to a Cosmos database. I could be saving it to somewhere else. Those are quite cheap, the Blob storage and S3. I could just save it somewhere else. It doesn't have to be those. It's more about like saying store it somewhere or save it somewhere. It's like, in the business logic, once the document is good, you've got the checkbox, then you want to store it somewhere. That's basically the name. You can actually say save or persist.

Participant 2: There is an anxiety of creating serverless applications. At large companies, we're putting a lot of focus on observability. What you showed us, it sounds really tempting, because we can deploy the same business logic to multiple clouds. Have you experience with observability? We haven't seen a lot of log messages in the code. Have you experienced putting the same observability on multiple clouds, on the same business logic, obviously.

Elena van Engelen: Yes. When you go to the non-functionals, then, of course, you have some difference. In the code, you don't have to have that. Usually, like with Spring, for example, you just say log info, and then you connect it to a specific logger. In the infrastructure setting, then you will say, ok, this logger will go to CloudWatch, whatever. That would be on your infrastructure layer. You don't have to change anything in your logging API when you log something. You do have to change something in your Infrastructure as Code if you want to direct it to some logging. Because you could be logging to a generic something that's not cloud-specific, or you could be logging to a cloud-specific, like CloudWatch. That's basically sending the messages to one or the other. It's the same. You will put it in the infrastructure layer. The actual loglines in your code won't change.

You just need to make sure that you use the API. Don't use the SDK of the cloud in your code. When you do logging, always use the generic logger and not the SDK-specific one. Just underwater, you should connect the SDK-specific one or where you want to log. I think it's similar to even if you're not moving to another cloud.

See more presentations with transcripts