Welcome my video about my presentation at the Kotlin London Community. Though online, the presentation went amazingly good. This session was about practical uses of Project Arrow that I found in my company to work for real life scenarios. Because it is not possible to talk directly about the actual code used in the project, I created a parallel world where we can use Project Arrow. Project Arrow is a functional library that we can use with Kotlin, to make sure that we use best practice related to functional programming theory. The idea is to maximize the potential of a functional code and adapt it to use with Kotlin coroutines as efficiently as possible. The initial idea was to give the presentation live and present in London, however, due to logistical issues, it was not possible to get everything managed on time. Still, it was an amazing crowd, an amazing audience and I just want to say thank you to David Craft for making this possible for me. Find all the necessary information about this meetup below in the description. For now, be sure to stay tech, keep programming, be kind and have a good one!
---
Chapters:
00:00:00 Start
00:02:11 Introduction
00:14:46 Overview
00:16:36 Functional Data Modeling with Arrow Core
00:20:42 NonEmptyList (NEL)
00:30:32 Error Handling with Either
00:34:14 Error Handling with Either in a cumulative way
00:39:12 Using option and nullable to handle non-existing results
00:50:45 Arrow Optics - The theory and practice of Lenses
01:03:21 Resillience with Orchestrated Saga
- https://dev.to/jofisaes/newscast-using-sagas-with-choreography-and-orchestration-patterns-kotlin-example-3ff6
01:12:09 Asynchronous data with Arrow FX - parZip
01:20:41 Suggesting STM video:
- https://youtu.be/DmV0bakYNps
01:20:54 Consistent state management with Arrow STM
01:29:33 Conclusion
01:32:56 Suggesting STM video:
- https://youtu.be/DmV0bakYNps
01:34:05 Questions - The Inquisitive Cat
01:36:27 Resources
01:36:51 About Me
01:37:10 Thank you!
01:39:51 End Note
- https://youtu.be/S3k6C1XaYr8
01:40:37 See you in the next video!
01:40:48 End credits
01:41:27 Disclaimer
---
Source code:
- https://github.com/jesperancinha/space-ship-adventures
---
Meetup Info:
- https://www.meetup.com/kotlin-london/events/306456259/
---
Sllides:
- Scribd: https://www.scribd.com/presentation/846009877/Boosting-performance-and-functional-style-with-Project-Arrow-from-a-practical-perspective-with-Spaceships
- Slideshare: https://www.slideshare.net/slideshow/boosting-performance-and-functional-style-with-project-arrow-from-a-practical-perspective-with-spaceships/277622766
- Speakerdeck: https://speakerdeck.com/jesperancinha/boosting-performance-and-functional-style-with-project-arrow-from-a-practical-perspective-dot-dot-dot-with-spaceships
---
---
Chapters:
00:00:00 Start
00:02:11 Introduction
00:14:46 Overview
00:16:36 Functional Data Modeling with Arrow Core
00:20:42 NonEmptyList (NEL)
00:30:32 Error Handling with Either
00:34:14 Error Handling with Either in a cumulative way
00:39:12 Using option and nullable to handle non-existing results
00:50:45 Arrow Optics - The theory and practice of Lenses
01:03:21 Resillience with Orchestrated Saga
- https://dev.to/jofisaes/newscast-using-sagas-with-choreography-and-orchestration-patterns-kotlin-example-3ff6
01:12:09 Asynchronous data with Arrow FX - parZip
01:20:41 Suggesting STM video:
- https://youtu.be/DmV0bakYNps
01:20:54 Consistent state management with Arrow STM
01:29:33 Conclusion
01:32:56 Suggesting STM video:
- https://youtu.be/DmV0bakYNps
01:34:05 Questions - The Inquisitive Cat
01:36:27 Resources
01:36:51 About Me
01:37:10 Thank you!
01:39:51 End Note
- https://youtu.be/S3k6C1XaYr8
01:40:37 See you in the next video!
01:40:48 End credits
01:41:27 Disclaimer
---
Source code:
- https://github.com/jesperancinha/space-ship-adventures
---
Meetup Info:
- https://www.meetup.com/kotlin-london/events/306456259/
---
Sllides:
- Scribd: https://www.scribd.com/presentation/846009877/Boosting-performance-and-functional-style-with-Project-Arrow-from-a-practical-perspective-with-Spaceships
- Slideshare: https://www.slideshare.net/slideshow/boosting-performance-and-functional-style-with-project-arrow-from-a-practical-perspective-with-spaceships/277622766
- Speakerdeck: https://speakerdeck.com/jesperancinha/boosting-performance-and-functional-style-with-project-arrow-from-a-practical-perspective-dot-dot-dot-with-spaceships
---
Category
🤖
TechTranscript
00:00On the 3rd of April of 2025, I presented at the London Kotlin community.
00:05My presentation was held online because of many reasons,
00:08but mostly because of the logistics needed to sort out
00:11before I could travel to London and be there on time for the meetup.
00:16And so we decided that we would do this presentation online.
00:20It went really well, and I enjoyed also participating in a Q&A session
00:24that was held afterwards.
00:26My session was about ways to use Project Arrow in projects,
00:32ways to use them in practice,
00:35because Project Arrow is a very extended project that has many different features,
00:40and we don't use them always,
00:42and we may not want to use all of them at the same time.
00:47Project Arrow is a library that we can use in our project
00:53to enhance the way we do functional programming.
00:57But I didn't want to talk about the specifics of the current project I'm using it already in,
01:03because, of course, I cannot talk directly about the implementations that we are using
01:07in my specific project in my company.
01:10And so I devised a plan.
01:12What I wanted to do is to create something new
01:15that would be a parallel to what we are using already.
01:18And that's why I came up with this project
01:22where we are talking about data transmission between spaceships.
01:26We are talking about docking a spaceship,
01:28we are talking about refueling a spaceship,
01:30and we are talking about accounts that may be given to users of that space station,
01:35which could be astronauts or anyone who is a part of the crew of the spaceship.
01:40So I found the topic to be interesting.
01:43And it gives a kind of sphere to what we want to achieve with this project.
01:51And so let's get into that presentation and let's see the examples.
01:57Let's go through the slides that I also showed in this presentation in the meetup
02:01and understand a bit more what Project Arrow can do for us in reality.
02:07So let's get into that.
02:08A little bit about me.
02:20I've been a software engineer for more than 10 years.
02:23And in this time, I have developed in different programming languages
02:26like Java, Kotlin, Groovy, and Scala.
02:29So essentially languages around the JVM.
02:32And I am the owner of the YouTube channel JasperTech.
02:35I am a certified Spring professional.
02:38I'm also a certified Java professional.
02:40I am a Kong champion, also recently an MVP.
02:44And in a nutshell, this is who I am.
02:45So in this presentation, we are going to see very different aspects of Project Arrow.
02:52And we are going to see why are we talking about this?
02:56How can we apply this?
02:58And what are the most useful use cases for this library?
03:02So the problems we are trying to solve are, for example, challenges in data transmission.
03:08What do we need to do to send data correctly through the wire?
03:11We need to think also, why are we choosing functional programming for spaceship data transmission?
03:19In any case, any kind of data transmission, why is it important for us to use functional programming?
03:25We also need to think, what is Project Arrow?
03:28And what does it mean to talk about Project Arrow?
03:34And why does this work?
03:36These are all questions that we are going to answer and topics that we are going to discuss throughout this video.
03:42So what are the challenges in data transmission?
03:46We need to handle transmission failures.
03:48So we need to have a good way of handling errors and a good way to discuss how errors should be handled
03:56and where and when can we interpret these errors.
04:01Important also is to ensure the message delivery order.
04:05How can we achieve a certain kind of order?
04:07And how can we achieve the expected result when we are sending messages?
04:12Especially if we are sending synchronous messages,
04:15what do we need to do to make sure that we get the message correctly from point A to point B?
04:23We also need to discuss encoding and decoding data.
04:26What does it mean to encode and decode data through the wire?
04:30These are things that are important when we are thinking about data transmission.
04:34What format are we going to use?
04:36Is it gRPC?
04:37Is it JSON?
04:38Is it XML?
04:39Are we doing more innovative things?
04:41Or are we doing still the typical standard that we are bound to deal with in current applications?
04:49Do we want to break through the rules?
04:53We need also to think about handling missing or corrupted data.
04:57So this is a bit different than transmission failures.
04:59Transmission failure is more related to if a message gets delivered.
05:04In this case, we are talking about a corrupted data, something that happened through the wire,
05:10or perhaps when we are sending the data or choosing what we want to fill in our data,
05:14that gets across through the wire and in the reception gets invalidated, for example.
05:20So how do we deal with that?
05:22And what do we do when the format or the data itself doesn't match the expected results?
05:32We need to make sure that we make good comment execution that is asynchronous.
05:37And the idea is that we will deal with back-off pressure and things like resilience in our services.
05:44And what does it mean to send these asynchronous commands to our services that will have to deal with many different requests at the same time?
05:51And then finally, we need to coordinate state.
05:56If there is a state between the two different ships, what does it mean to coordinate that state?
06:01And how can you guarantee that our state doesn't get into a blob of mess?
06:07So we need to make sure that if I perform something in a transactional way, and it is already a hint,
06:14that the state doesn't get corrupted in any way.
06:20So these are basically challenges that we face with data transmission in general.
06:25It doesn't necessarily mean that we are going to deal with all of these features of Project Arrow,
06:31but it does mean that these are things that we need to keep in mind when sending data through the wire.
06:37But why functional programming anyways?
06:40Why do we need to choose functional programming?
06:43And do we need to choose functional programming?
06:46Now, one of the things that functional programming relies on is that our data is immutable.
06:52And so that means that all through our code, we are able to predict where the data is at.
06:57We are able to say that from A to B, through all of these different function calls, our data will not be changed.
07:05That is what immutability guarantees us to do.
07:08And that is why it is so handy to use with data transmission.
07:16Functional programming also relies on error handling without crashes.
07:19So this means that there are ways to deal with errors without having to use things like try-catch, for example.
07:26Or perhaps even if we use try-catch, that we have an elegant way to deal with the way errors are being thrown.
07:35Functional programming works in such a way that it is much more easy to implement things like resilience and automatic recovery.
07:42If we think about how we make code, especially if you are coming from a Java background, the old Java background, not the new, because the new is different.
07:52But if you come from the standard way of programming in Java, or even the standard way of programming in Kotlin,
07:59you will find that doing automatic recovery and making resilient systems can result in a complicated code.
08:08It doesn't have to, but this is something we want to avoid.
08:11And of course, Project Error comes here and fits very well into this part of a feature that we want to add to our project.
08:23Functional programming matches really good and fits like a glove when we are talking about concurrency with reduced complexity.
08:32In the world of Kotlin, we've got something called Kotlin coroutines.
08:36And Kotlin coroutines are ideal when we are trying to deal with concurrency.
08:40And we are trying to remove complexity.
08:44It depends on what we are using.
08:46In this case, for example, if we are using Spring, we will still have to use things like Suspend, which adds some complexity to the code.
08:53If we are using things like Ktor, which are inherently synchronous and are inherently adapted to work with coroutines,
09:02then we probably won't even see the Suspend keyword ever, which is also why I chose Ktor to use in these examples,
09:10so that the Suspend keyword doesn't bring some confusion in trying to understand how the code works.
09:15Mathematical guarantees for safety.
09:21This is something that happens implicitly in our code if we are using Project Error and Kotlin in general.
09:27And also other languages like Java, for example, also use this.
09:31The thing is that we don't think about this.
09:33And what this is about is monad theory.
09:36We are talking about using functors, using monoids, and using monads in our project.
09:43And therefore, we get mathematical guarantees that our code will work.
09:47Because monoids, monads, and functors are part of a general mathematical theory that is applied in programming
09:56and has been applied for a long time in different programming languages, like, for example, Haskell,
10:02which is something that always comes up when we talk about these concepts.
10:06But in any case, this is just something to keep in mind when we are working with functional programming and using Project Error.
10:12So, two important examples of these concepts are implemented with option and either,
10:20which are also things that we are going to see later on.
10:25Declarative and composable pipelines.
10:27When we are using functional programming, making declarable and composable pipelines is much easier
10:33than using standard object-oriented programming.
10:37And that, of course, with Kotlin is enhanced and is made a little bit better
10:41because Kotlin is focused on functional programming.
10:44But also, with Project Error, we will see functionalities that will allow us to compose different elegant pipelines
10:50so that we can get our results and implement the features that we require.
10:54Finally, the most important aspect of functional programming is this concept about pure functions.
11:02When we are using Kotlin, even just using Kotlin, sometimes it's difficult for us to make code that is pure.
11:09Now, the concept of pure may sound a bit unfamiliar or even silly when we talk about it
11:16if we don't know the theory behind what it means to say pure functions.
11:22Pure functions are functions that essentially don't cause side effects.
11:27They are not dependent on external factors like, for example, global variables or fields of the class.
11:33They basically work isolated, and that means that when we call these functions,
11:37we are sure not to affect any kind of state that our instance may have.
11:44And that's what means here to be pure.
11:48And this is important because of predictability and all sorts of different benefits that we will wreak from using this.
11:54But what is Project Arrow?
11:59Project Arrow is a functional programming library.
12:01I just put the definition here for Kotlin that provides tools for typed error handling, concurrency, resilience, optics, and functional data structures.
12:11It helps developers write safe, composable, and declarative Kotlin code by leveraging functional concepts like option, either, and optics.
12:19Now, this is a very short way to describe Project Arrow.
12:25However, Project Arrow is a very broad, and it's becoming more and more and more extended,
12:31and it has more and more features that allows us to do all of this and more.
12:38And the key features here that we may want to use with our projects are the typed error handling with either an option.
12:46We may also want to use functional concurrency.
12:49There's an error, fx, coroutines for structured parallelism.
12:52This means that we can use different functions that allow us to compose in different ways, different streams,
12:58and especially if we want to deal with them in parallel.
13:01Maybe we want to join one stream with the other in parallel, and we can do that already in Kotlin.
13:05But with Project Arrow, we can really make that code much easier to understand,
13:11and we can also make sure that our code base doesn't get too big.
13:16Resilience tools like Retries, Sagas, and Circuit Breakers.
13:20In this presentation, I'm just using Sagas because Sagas is something that revealed to be very useful.
13:26The other two and more different patterns that we can implement surrounding the theme of resilience.
13:34They are also very useful, but it is something that perhaps are more inclined to be used in a niche situation.
13:44But in this case, Sagas is what we are going to talk about in this presentation as well.
13:48And then it also provides immutable data manipulation.
13:51And this is important because when we are using immutable data, we may want to change it.
13:57And that could be a cumbersome process if we are dealing with deeply nested data classes.
14:04And those data classes, especially if they are very, very deeply nested, can become a problem
14:09because I'm sure you've dealt with this before where you need to do a get before you put a set,
14:14and then you need to make a copy of a certain object,
14:17and then you need to make that copy in a way that that property is affected.
14:22And then you need to make the copy of all the different bound, sub, or other different nodes that are above.
14:30Parent nodes, the child nodes, you may want to copy everything.
14:33And that can be very cumbersome.
14:35With Project Arrow and Optics, this works really, really easily.
14:39And I will talk about this in this presentation as well.
14:41So the overview of the project that we are dealing with is essentially this.
14:49We've got two different spaceships.
14:50They are communicating with each other.
14:51They are in space.
14:52They need to dock.
14:53They need to refuel.
14:54There are astronauts in them.
14:56And they both have a sender module and a receiver module.
15:00And essentially, this is just an overview of a project that is developing, and it's not finished.
15:05And it will probably never be finished because the project is intended to continue to explore the aspects and the different features of Project Arrow.
15:13But essentially, this is what we are having a look at today.
15:16And it is important that we focus here and bear this in mind so that we get a kind of atmosphere surrounding our code,
15:23because I think that helps understanding code a little bit better.
15:26So let's now find this in a more structured way.
15:31This is just a very simple diagram, and there's nothing special to it, except that it explains the different topics that we are going to talk in this presentation.
15:41The first one is STM.
15:43That means Software Transactional Memory.
15:46That is something to deal with different aspects of changing values of a state.
15:53So we will see how can that help us in making sure that our state doesn't get corrupted.
15:59We've got Arrow Core, which is necessary for us to use simple things in Project Arrow.
16:07Arrow Handling, we're going to have a look at either.
16:09And Option.
16:11Concurrency.
16:12How can we deal with different streams, and how can we deal with different coroutines being launched in parallel in different threads?
16:18Then we are talking about Resilience.
16:19In this case, as I mentioned before, we are going to talk about Saga.
16:22And Optics.
16:24How can we deal with deeply nested classes, and how can we deal with these instances and make changes to them in a way that our code doesn't get too big or too complex?
16:37So let's start with Functional Data Modeling with Arrow Core.
16:41There are different features that we can use with Project Arrow that will help us modulate our data better.
16:46And one of them is Option.
16:49And Option allows us to deal with nullable values.
16:52We can already do this with Kotlin and other programming languages of the JVM ecosystem.
16:58One of them is using the traditional if.
17:00The other one with Kotlin is using the null coalescent operator or using the question mark when we are dealing with values.
17:07It's all about that nullability concept and the way to make null safety possible in Kotlin.
17:14But with Project Arrow, we can do that in a functional way.
17:17We will see that form further down in this video.
17:22Then we've got the concept of EIDER.
17:24In a nutshell, EIDER means that we have two different subtypes, a left and a right.
17:28On the left, we accumulate or we put in the first error that we get by a function call.
17:34Or we put the result of the function call on the right value of EIDER.
17:40So EIDER can have one or the other, and we will see how can we modulate this to our needs in our code.
17:48The other concept is data validation and error accumulation.
17:52So how can we validate data and accumulate the errors?
17:56Error accumulation is something that different frameworks already provide.
18:01For example, the Spring framework allows us to, for example, annotate different entities or different DTOs
18:09and accumulate all of the different validation results in a list, for example, or in a validation object.
18:17There are different ways to do that.
18:18With Project Error, we can do that also in a functional way.
18:21And that means that we can get all of the errors in an EIDER type, where the subtype left will contain a list of all of these different errors.
18:30And those different errors will be inside a list of type non-empty list.
18:37And the reason for that, think about it.
18:40If we are getting an error, then we need at least one error in it.
18:44So it makes sense to use a non-empty list.
18:46Or, in its short form, null.
18:49But we will see that non-empty list can give us different ways to validate our objects, our DTOs, for example,
18:56if we need this kind of requirement.
19:01And finally, another thing that we want to have a look when we are modeling data in Project Error or with Project Error,
19:08is this concept of lenses.
19:10Lenses are integrated in a more global concept called Optics in Project Error,
19:16where it also includes things like prisms.
19:19But prisms is kind of a niche thing for a niche goal.
19:22And that goal wasn't applicable in our case.
19:26But lenses were.
19:27Because lenses allows us to deal with data that is deeply nested.
19:31As I've mentioned before, it is important that we can shortcut the changes that we want to perform
19:36in our deeply nested data structures, should we use those data structures.
19:42So let's now have a look at the data model that we want to use to exemplify these different concepts.
19:48Now I've got here three different types.
19:51A transmission ngDTO, transmission new generation DTO, a message package, and a message.
19:57So the way this works is we've got a transmission DTO that has a message package.
20:02That message package is a package that wraps around a list of messages and a timestamp.
20:09And inside that list of messages, we've got different messages of type message that will contain an ID,
20:14a purpose, a message, a message BCC, and a message CC.
20:17This is just a data structure for an example of transmitting data between two spaceships.
20:23And we can see already that we've got this annotation right over here, optics in here, optics in here, optics,
20:30because these examples are also made to exemplify project arrows, optics, and specifically in this case, lenses.
20:42The first concept that I want to show actually is non-empty list.
20:46So let's begin with a simple idea.
20:48A list can be empty, right?
20:50What if I want the list to contain one single element, and I want to validate that?
20:56What should I do?
20:57Should I just validate it?
20:59Should I use a validation function?
21:01I mean, that could introduce different side effects.
21:06And in a pure world, that is kind of risky to do.
21:09Because I just want the list to not be empty right off the bat.
21:12I want to validate for it, but I don't want to use extra code for that.
21:17I want this to be as seamless as possible.
21:21This is where our hero comes in, our non-empty list, because it has a contract.
21:26And the contract says, I am a list which is not empty.
21:30And if we try to put a list that is empty there, it will just fail.
21:34So this means no more concerns about null values, no more empty headaches, and no more runtime surprises.
21:43So in our example, we've got a non-empty list that we are using in the class message package.
21:49But what's important here is that we first understand what this class is for.
21:54Now, in detail, we've got a custom serializer.
21:57And the reason why a custom serializer is here is because Ktor doesn't give us all the serializers by default.
22:05And some of them we need to define manually.
22:07We will see this in the code, but it's not the important bit of this class.
22:12The important bit of this class is, of course, our hero, non-empty list.
22:17And the non-empty list will validate that our list is not empty, as we have seen in the example.
22:22Now, if we look at our example now in the code, this is our example project.
22:27It's called Spaceship Parent.
22:29And Spaceship Parent is available on GitHub under my handle jshponensigne.
22:33And we can find the source code of the project in this module app.
22:38If we go into app, we will find the different structure related to the application that we are running.
22:45This is a service.
22:46And just to give you a general idea, I've got here the application starting with engine main.
22:51This is something that is related to Ktor.
22:54And if you are familiar with it, you know already what it is.
22:56But essentially, if you are also familiar with Spring Boot, it's just a way to start our application
23:01with all the context and every little detail needed to run Ktor.
23:07It's got here the different configurations that is necessary to run this application.
23:11But the important bit here is that we look now at the non-empty list.
23:17And if I just search for non-empty list, then I will see lots of different usages of this in the code.
23:26But the one that we are more interested in is this one over here in services.
23:30And if we go here, we will see that we have got the definition of message.
23:39And then here we've got the definition of package in Spaceship videos.
23:44And here we've got message package with serializable, which is needed to be able to serialize optics,
23:54which is something we will see later on.
23:56Our serializable here.
23:59Another serializable here for local date time.
24:02And this is the local daytime serializer.
24:05Now, before we continue, let's have a look at the non-empty list serializer.
24:08It is essentially a K-serializer that implements two different important functions.
24:14These are the serialized and the deserialized.
24:17And here we can then see that our lists are correctly serialized and deserialized.
24:23This is important because we want to be able to send our data via the wire through our endpoints
24:29that will get the messages that we want to send.
24:33So if we go back, we've got here the most important part that we want to deal with right now.
24:38And that is the non-empty list.
24:40If we send messages with an empty list, this will not work.
24:44And if we send them with at least one element in them, then this will work.
24:49To test that, I've got different test cases for it.
24:54And let's just first see where this is being used.
24:58If we go to services and we go all the way to how this is implemented,
25:07this is essentially a service layer that creates different things for us.
25:11If we call these methods, for example, here, create transmission,
25:15it will create a transmission DTO in the database.
25:19And it will essentially return its counterpart, which is in this case,
25:23an EIDER that contains the transmission new generation DTO and a string.
25:29So here in string, we will register in a string form our errors.
25:33And here we will register the actual value that we want to get from that function.
25:38But this is EIDER that will be for later.
25:39What we want to do now is test the route.
25:42And for that, I've got one specific route that is specifically made for this example,
25:47which is spaceship routing.
25:48It could change in the future.
25:49But what it has now is a POST request implementation,
25:54a POST endpoint,
25:56which is this one over at transmissions.
26:02And it's called...
26:11this one.
26:14This one over here is the POST endpoint,
26:16where we will receive a transmission DTO.
26:19This way, this is the KTOR way to receive data from the endpoint,
26:23call.receive.
26:25And then here we create a transmission and we put it in the database.
26:27If something wrong happens, we will get an error.
26:30In this case, we will get an internal server error,
26:32or we will get a response.
26:35This is already using EIDER,
26:36but for us, the important bit is what happens between sending the request
26:41and the receival of the actual DTO,
26:45which is this one over here, the transmission new generation DTO.
26:49And in order to test this,
26:50let's just go to our scratch pad,
26:52which is this one over here.
26:53I've got here requests.
26:55And this request.http is a file with all the different examples
26:58that we want to use to test the different parts of this presentation.
27:03So if we go all the way up to here,
27:08we can see that we've got a POST to transmissions,
27:11the one we've seen before.
27:12Let's go back to it again and see if this matches.
27:14The route is called transmissions.
27:18This one over here.
27:19And if we go all the way down,
27:20we see that the node is the same,
27:23and then it will fall into this POST endpoint,
27:25which is the one that we are testing right over here,
27:27which is where we are using HTTP slash localhost 8080 transmissions.
27:34Now, if I send this,
27:36it will fail because I didn't start the service,
27:39so I will start the service now.
27:59Cool.
28:00Okay.
28:01Now, the service has started.
28:03Let me just close this
28:04so we can get a better overview of what is happening.
28:07We can see it's already creating different tables.
28:10We can see that it's creating the message packages,
28:12the messages and the transmissions.
28:14In the background, this is using exposed,
28:17and this is akin to using the JPA in the Spring framework,
28:21but that's not relevant for the tests that we are doing.
28:24What is relevant for the tests that we are doing
28:26is that we send this request,
28:27and we see now that no error is being reported.
28:29We can see that we have our data
28:32inserted in our database,
28:34and we get the result correctly,
28:35because when we are returning the result,
28:38we are folding the IDER,
28:40and therefore, we are getting either the created with an IT,
28:43which is the actual result,
28:45which is the actual transmission that has been saved in the database,
28:48or we get an internal server error.
28:50In this case, we don't get an error.
28:52We get everything correct,
28:53but what we are going to do right now
28:55is try to send a data without any single message.
29:00So in this case, we are sending messages,
29:02but we are sending an empty list.
29:04So if we send this now according to the new contract
29:06that says that our list must have one single element,
29:10this should fail.
29:11And that is what we are going to test right now
29:13in this point,
29:16where we see that it immediately says
29:18that it failed to converse the request body
29:20to the DTO that we wanted,
29:23the transmission and GDTO.
29:25And this happens,
29:26if we get a look at the exception,
29:30this happens right at the post-transmissions,
29:33at the endpoint where we specified
29:35that we wanted to send the new transmission
29:38without messages.
29:39Because, of course,
29:40if we are sending a transmission,
29:42we need messages.
29:43That is the whole point of sending a transmission.
29:44And so in this case,
29:45we've got an automatic validation
29:47just by using the type
29:48without the need to use
29:49any particular complex system
29:51of manual validations
29:53or just using annotations.
29:54In this case,
29:55the type itself validates for a non-empty list.
29:59But you may have noticed as well
30:01in the code,
30:01as I was running through it,
30:03that either
30:04seems to be using something
30:08and that is something else.
30:09That is a non-empty list as well.
30:12But before I go into that,
30:14let's now have a look at either
30:15and what it means.
30:17So if we go here to the presentation
30:18and we go to the next slide,
30:21we will find the error handling example.
30:25And in here,
30:26we see an example of using either.
30:28Let me tell you something about either.
30:30Either can be your new best friend
30:31in error handling
30:32because handling errors
30:33don't have to be a headache.
30:35It is a reliable,
30:36no-nonsense solution
30:36to getting what you want
30:37or dealing gracefully with errors
30:40when things go sideways.
30:41Imagine either as a two-sided coin,
30:44one side is right
30:46where everything goes according to plan
30:47and the other side is left
30:49where all the error and issues live.
30:51But either makes them all feel welcome.
30:54Imagine either being that friend
30:55that never comes empty-handed to a party.
30:57So back to our slides,
31:00we can see that the example
31:01that we have here
31:03is a validate transmission function
31:06that returns an either
31:08of a string or a transmission ngDTO.
31:11String being the error
31:13and transmission ngDTO,
31:16what we want to get,
31:17our goal,
31:17what we want to achieve
31:18from the call of this function.
31:21So that means that we return an either.
31:23And if you can see over here,
31:25we've got either
31:26and then inside,
31:27we've got the body of either.
31:29This is a function body
31:30that will perform different operations.
31:33And two of them are ensure.
31:35And this ensure over here,
31:38what it does,
31:39it simply makes a call
31:40to something that will validate something.
31:42In this case,
31:43it will ensure that the sender is not blank.
31:45And it will also receive as an input,
31:48a function that will say
31:50sender cannot be blank.
31:51It will return a string.
31:54And that is the type of either.
31:56That is the type of the right in either.
31:59And then at the end,
32:00it will return the successful operation
32:02transmission ngDTO
32:03when all the validations
32:05have been successful.
32:08So in this case,
32:09what we've got here
32:09is the left and the right,
32:10as we have mentioned before.
32:12Left, a string.
32:14Right, the transmission ngDTO,
32:15which could be anything.
32:16You could also use exceptions here.
32:19It doesn't have to be exceptions.
32:20I didn't use exceptions here
32:22because I want to make this
32:23as simple as possible
32:24so that we can understand this quicker.
32:28Then I've got also the either.
32:32As I mentioned before,
32:33this runs a computation block
32:35using raise
32:36and returns its outcome as either.
32:39So raise is the function
32:42that we are using here.
32:44And in raise,
32:44we are using the ensure
32:46that will allow us
32:47to run these validations
32:50and make sure
32:51that our received object
32:54or our created object
32:55matches what we expect
32:57and validates the way we expect.
33:01We also have got
33:02this validations implementation,
33:05which ensures that the condition is met.
33:06Otherwise, raise raises
33:08a logical failure of type error.
33:10Now, sender is not blank
33:13and receiver is not blank.
33:15It's simply an expression
33:17that can return a false
33:19or a true.
33:22And that is the way
33:23we do validations this way.
33:24This is done in a functional way.
33:26And as you can see,
33:28if the code goes well,
33:29it goes completely
33:31from beginning to the end.
33:34There are no loops.
33:35There are no ifs.
33:36There is no return call.
33:38There is no throws.
33:39It just goes with the flow.
33:42An error that can possibly occur here
33:44will be stored in string
33:46in the left value.
33:49And it will be accommodated very well.
33:51And either will give a room for it,
33:53a little house
33:54that we can then use
33:55for other validations along the line.
33:57We can then use fold,
33:58fold map,
33:59different kind of functions
34:01that are typical
34:02and are available with either.
34:06But we may want
34:07to accumulate these errors.
34:09And that is what we will see
34:11in this next slide
34:13where we can find
34:15a zip or accumulate function call.
34:18And the zip or accumulate function call
34:20is very interesting
34:21because we can use it
34:21in the body of either.
34:22And then we can then call ensure
34:26as many times as we want
34:29inside the validation function.
34:30So we can see now
34:33that the zip or accumulate
34:34will accumulate all the errors
34:36or the right value.
34:39But let's now see this
34:41in practice how this works.
34:42So if we go to our project,
34:44we can then see
34:44that we've got here
34:45zip or accumulate.
34:47We've got here the ensure,
34:49the other ensure,
34:50and then we've got these two
34:51ignored input parameters.
34:54Now the reason why I did this
34:55is because I want to highlight
34:57the fact that we can
34:58accumulate the errors
34:59and then we can also
35:01create our object
35:03if all those validations
35:04have gone through.
35:05And if not,
35:05we return a list of the errors
35:07which are now a non-empty list
35:09of all the strings
35:10that have been generated
35:12that are a part of the errors
35:14that occurred
35:14while trying to validate
35:16our object with zip or accumulate.
35:19But the thing is,
35:20in each one of these validation functions
35:22that we can add here,
35:23we can also return values.
35:27So let's say for example
35:28that I would go over here
35:30and say that I am returning a.
35:32So the last expression is a
35:34as a string.
35:35If I go here
35:36and I call this a for example,
35:38we can see that this is a string now.
35:40If I say for example,
35:41true,
35:43we'll now see that a
35:45is a boolean.
35:47And this can be useful
35:49after validating functions
35:51because I can also say here
35:52for example,
35:53that I want to use a sender.
35:54and now the sender is a string
35:57and I can return here the sender.
35:59I don't need to use the sender here
36:00as the input parameter
36:02of the function.
36:03I can perhaps use this here
36:04and perhaps make the code more readable.
36:06Or maybe use it
36:08in other different ways.
36:10We don't have to use it this way,
36:11but it's one of the ways
36:14that we can use this function as well,
36:16not only to accumulate errors,
36:18but to return values
36:20after each error has occurred or not.
36:22If a error does not occur,
36:23what value do we want to return
36:25and where does this value
36:26needs to go to
36:27upon the generation
36:28of the object that we want to get
36:29or what we want to get
36:31from the function
36:32when we are calling this.
36:33And remember,
36:34this is an invoke,
36:35so here we can also create
36:36an object of type
36:38transmission ngDTO.
36:44So now we see an example
36:46on how to use zip or accumulate,
36:48but we have not seen yet
36:49how does this actually work.
36:51So if I go here
36:52to the invoke test,
36:54then we can see the shape
36:56that this can take
36:57if we put wrong validation.
36:58So let's first look in detail
37:02what validations are we making.
37:03So we are making sure
37:04that sender and receiver
37:05are not blank.
37:06So in our tests,
37:08if we send on purpose
37:10senders and receivers
37:12that are blank,
37:14these ones over here,
37:16if I send this,
37:17I should get errors.
37:18And how many errors
37:20should I get
37:20in transmission ngDTO?
37:22So here,
37:24this, by the way,
37:25is not a transmission ngDTO.
37:27This is a transmission,
37:29this is more like
37:30an either.
37:32Because remember,
37:33either will accommodate
37:35both errors and successes,
37:38and they are mutually exclusive.
37:42So that means
37:43if we get a success,
37:44we will not be getting an error.
37:46If we get one error,
37:47then there will be no success.
37:48And one error alone
37:49is a reason to create a list,
37:51which is a non-empty list,
37:53which has at least one error on it.
37:55All right.
37:55So now let's just run
37:57this test in debug mode,
37:59and let's see what happens
38:00in the result.
38:02Remember,
38:02we are now sending
38:03a transmission
38:04that has two errors.
38:06And when we get the validation,
38:08we should get just that,
38:10two errors in our transmission
38:11ngDTO,
38:13which is what we are getting here.
38:15We are getting
38:15two different messages.
38:16One says,
38:17sender cannot be blank,
38:18and the other one says
38:19that receiver cannot be blank.
38:21So we are essentially
38:22accumulating the two errors
38:23with also the possibility
38:25of using results
38:27after performing
38:28the validation
38:29of each one of the fields
38:32that we want to validate.
38:33In this case,
38:34with ensure,
38:35we could just have added here
38:36something at the end,
38:37and we could have added here
38:38something at the end
38:39and use it here
38:40as the input parameters
38:41to create our transmission
38:42DTO,
38:42or whatever we want to return
38:44in this invoke function.
38:48All right.
38:49So now we have seen
38:50the non-empty list,
38:52the null,
38:52and we have seen
38:54the either.
38:56And one of the things
38:57that in the presentation
38:58I didn't talk about
38:59in the slides
39:01is the option.
39:04And what do we do
39:05with this nullable thing
39:06that we have mentioned before?
39:10Let's now have a look
39:11at nullable.
39:12But here's the interesting thing
39:13about option.
39:14Knowing this,
39:15we can say that option
39:16combined with nullable
39:18provide us exactly with what?
39:20Let's face it.
39:21Nulls happen.
39:22Sometimes the value
39:23that you are expecting
39:24is somehow sipping
39:25piña coladas
39:26in a parallel universe.
39:28But don't panic.
39:29Arrow's nullable function
39:30is here to turn
39:31your Kotlin mess
39:32into a functional bliss.
39:35Not only nullable,
39:36but also option.
39:38With nullable,
39:38you can embrace the void.
39:40And with option,
39:41you can embrace the none,
39:42or the sum,
39:44where sum says,
39:45yep, I've got it,
39:46and none says,
39:47there's nothing here to see.
39:48And all of this
39:49without seeing
39:50a null pointer exception
39:51blowing up
39:52in your application.
39:54So nullable,
39:54I've got it in the project.
39:56I don't have it
39:57in the documentation.
39:59And we can have a look
40:00at it.
40:00For example,
40:01this one is
40:02an interesting one,
40:04but I have a better
40:04example of it.
40:05So we'll look
40:06at nullable,
40:07and then go
40:09to the project.
40:11And then I believe
40:12this one
40:15could be a good one.
40:18Yes,
40:18because this one,
40:21just first stop this.
40:24Now let's go
40:25to nullable.
40:26Let's go to,
40:32let's try
40:33this example.
40:35This is a good one.
40:37So this is
40:38a retransmission example.
40:40And what this does,
40:41it will check
40:41for every message
40:43if the message cc
40:45or the message bcc
40:46is null or not.
40:48If it is null,
40:50then what will happen
40:52is that the return
40:54of this nullable
40:57will be null
40:58if message bcc
41:00and message bcc,
41:02each one of them,
41:03if any of them
41:04is null.
41:05This bind
41:06will short-circuit
41:07the function
41:08and make sure
41:09that here
41:10we will get
41:11a null value.
41:11So let me just
41:12first refactor that.
41:13Let's just call this
41:14a nullable result.
41:17And then
41:18here we can just,
41:19let's just print
41:20to the console
41:20the nullable result.
41:24So that means
41:25that if we happen
41:26to get a message cc
41:27with a null value
41:28or a message bcc
41:29with a null value,
41:30any one of them,
41:31then we will be getting
41:32a null value
41:33that will print out
41:34to the console value null.
41:36So let's now
41:37get the retransmissions endpoint
41:40in the example
41:41in the scratchpad.
41:45So this is one
41:46that is retransmissions
41:47and we can see here already
41:48that we've got message cc
41:50and message bcc
41:51with some values.
41:54And here we've got nothing.
41:57And here we've got bcc
41:58and message cc again.
42:01If we go to our code,
42:03we see that we have printed it.
42:05But we are also seeing
42:06an interesting thing.
42:08And that is
42:08that for each one of them
42:11that is successful,
42:12it will print out
42:13the full message
42:13to the console.
42:14If it's not successful,
42:16nothing normally would happen.
42:18It's just that now
42:19I've printed nullable result
42:20and we should now see
42:21null in the console.
42:22So if I now call this endpoint,
42:24with this message,
42:26how many full messages
42:27you think you will see
42:28in the console
42:29and how many null values
42:31do you think
42:31you will see in the console?
42:33We will see one null value
42:34in two messages, right?
42:35Let's check if that's true.
42:39But before I do that,
42:41I do want to
42:42put some breakpoints here
42:44so that we see
42:45the short-circuiting function
42:47of this call.
42:49And let me just add
42:50to the example
42:51yet another message
42:54which is going to be
42:57a message
42:57without a BCC
42:59because I do want
43:03to show the effect
43:04of short-circuiting.
43:07So actually,
43:08we will see
43:09short-circuiting before.
43:11Let me just get
43:12this one out
43:13and make sure
43:14that we do get a BCC
43:15but we don't get a CC
43:16because CC gets checked
43:17the first time
43:19and that means
43:20that we will see
43:21a short-circuit
43:21way before.
43:23So now,
43:23let's send this message
43:24and make sure
43:25that we can
43:27follow the code
43:31and that we can debug it.
43:32So let's now run that.
43:38We've got a connection refused
43:40because I stopped the service.
43:42So I will start it again.
43:43All right.
43:45Now if I run the service now,
43:47I will see
43:48we'll need to start it
43:52in the debug.
43:56So I've got the service
43:57started now.
43:58If I run this,
44:00I've got the endpoint here
44:02and I see now
44:03that we've got
44:03the first message
44:05that contains
44:06all of this
44:07and the first message
44:09is the it message
44:14and right over here
44:15we can see
44:15that it has the purpose,
44:16the message,
44:17the BCC,
44:17the CC.
44:18So it's got everything.
44:19So if I let it run
44:20towards the next message,
44:23we should see it
44:24printing out
44:25the complete message.
44:28Let me run it again
44:29to the next one.
44:30Now let's check the console
44:31and see what happened.
44:32In the console,
44:33we've got the full message
44:34that is being printed out
44:35to the console.
44:36So nothing much happened here
44:37because message cc
44:38and message bcc
44:39are not null.
44:41In this next message,
44:42if we see the result
44:44in the IT,
44:55we will now see
44:57an interesting bit
44:58which is the BCC is null
44:59and the CC is null.
45:01So the first thing
45:02that we will see
45:03if we run one step further
45:05this will now go back
45:08and we'll return a null
45:09and we will print
45:10a nullable result.
45:13Go over here.
45:14It's already returned
45:15and we've got a null result
45:17because one single value
45:19was null.
45:20It short-circuited here
45:22and now we've got a null.
45:25The third message
45:27is a valid message
45:28because it's got
45:29a BCC
45:31and it's got a CC.
45:32So this one should go
45:33very smoothly
45:34and it should go
45:35to print it out
45:36in the console.
45:37This will print
45:38each successful message
45:39two times.
45:41I made this very fast.
45:42So if I go here now,
45:44I should be getting
45:45this one.
45:46I've got this unit.
45:48I've got this one.
45:50Yes, because
45:51I am printing out
45:52to the console.
45:53Actually,
45:54let's leave it this way
45:55because when we do a print,
45:57we return a unit
45:58and that's why
45:59it is printing now
46:00a unit instead of null.
46:01But we can see the difference
46:02between one and the other.
46:03So if we now
46:04run this one,
46:06remember,
46:06we are sending this message
46:07with a BCC
46:09but without a CC.
46:11So if we do this now
46:12and we run it,
46:14we will see that
46:14it short-circuits immediately
46:15because it doesn't have a CC
46:17and it will print out null
46:19to the console.
46:20So right now,
46:21we've got exactly
46:22what was expected.
46:24So we've got a message,
46:25we've got the unit
46:26that represents
46:26that a message was valid.
46:28The other one is a null
46:30because nothing was printed.
46:31The function was short-circuited
46:33over here in CC
46:34which all of them are
46:35at this point
46:36with these examples.
46:37And then the third message
46:39we printed out correctly
46:40with the result of a unit
46:42after printing out
46:43to the console.
46:44And then the last one
46:45is a null
46:47because the last one
46:48does have a BCC
46:50but it does not have a CC
46:51and it's also being
46:52short-circuited here.
46:53But this is not
46:56option yet.
46:57Option is something different.
46:59Option
46:59is an example
47:01that I have here separately
47:02and I did it this way
47:03because option
47:04is something that
47:05it's difficult to find
47:08a real use case
47:10to use option
47:11because we
47:11eventually need to use option
47:13to transform our data
47:16and when we are using that
47:17with the Spring framework
47:18in JPA
47:19we don't really use option
47:21that much
47:21and so we are more
47:23inclined to use
47:24the null values
47:25we are more inclined
47:26to use that nullable
47:27but nullable
47:28can be used
47:29in the same way
47:30as option can be used
47:31and with option
47:32we will see
47:33how this works right now
47:35but with simple
47:36mathematical calculations.
47:37If I go here to compute
47:38enter the test
47:39that runs compute
47:40I've got here
47:42an end point
47:43that says
47:45no binding
47:45and another end point
47:46that says binding
47:47no binding
47:49means that
47:50we've got
47:52a none value
47:53that will bind
47:55and if this value
47:56is a no value
47:58is a none
47:58then that means
47:59that the binding operation
48:00will short-circuit
48:01in the same way
48:02that nullable short-circuits
48:03when the value
48:04is null
48:05so bind here
48:06has that action
48:07has that potential
48:08to short-circuit
48:09the function
48:11if a match
48:12doesn't occur
48:13and in this case
48:13it's just a match
48:14with the none type
48:16so option has got
48:17two subtypes
48:18sum and none
48:19if it is sum
48:20then it's okay
48:20bind doesn't do anything
48:21and if it is none
48:22it short-circuits
48:23the function back
48:24so we've got this
48:26on an end point
48:27and we also have got this
48:30in a unit test
48:33so I don't really need to run
48:34to make this test
48:36but the idea here
48:38is that when we run
48:38this unit test here
48:41then what will happen
48:42with compute
48:43is that it will short-circuit
48:45here and it will not
48:46return a plus b
48:47let's see what happens
48:49if I run this test
48:50so if I run it
48:52I see that the code
48:55has gone all the way
48:56to where I expected
48:57to the b value
48:59it will try to assign
49:00a value to b
49:01but there's a bind here
49:02on a none
49:03if it is none
49:04it should short-circuit
49:07and that's what it does
49:08it's already in the return
49:09a plus b did not occur
49:10and the return
49:11is a none
49:13if we let it go
49:15the test is successful
49:16because the return
49:17is just a none
49:18no operation was made
49:20whereas in this case
49:21we should be getting
49:23a sum
49:23with value 30
49:25this is just a way
49:25to create sum
49:26in Kotlin
49:28with project arrow
49:29so sum
49:31is part of the arrow core libraries
49:33and we can use it here
49:34very well
49:35and if we do this
49:37we will get
49:39a plus b
49:40which in this case
49:41is 10 plus 20
49:44if I run this now
49:45we will see that
49:48no short-circuiting
49:50is occurring
49:50and essentially
49:51the result is 30
49:53you can also
49:53debug it for you
49:55you can see that
49:56we've got 10
49:5820
49:59these are two
50:00different sum values
50:02and because they are sum
50:04we
50:05after binding them
50:07we get the actual value
50:08so this is a bit of
50:09redundant operation
50:11but it's just here
50:11to give the example
50:12of what bind can do
50:13because bind will only
50:14be able to
50:16be used
50:17in sum or none objects
50:19essentially in option
50:20type objects
50:22and then here we've got
50:23the sum of a plus b
50:24which then means that
50:2510 plus 20 is 30
50:27so it returns a 30
50:28and in order to be able
50:31to check that 30 works
50:32this return is being made
50:34under option
50:35and that means that
50:36the return will be
50:36sum 30
50:37and that's why
50:40the tests run correctly
50:42and now it's time
50:44to have a look at
50:44optics
50:45and optics
50:46it's a great thing
50:48this is how we install it
50:49but let me tell you
50:50a bit first about optics
50:51did you ever feel like
50:53you're navigating
50:53through a never-ending stack
50:54just to get that
50:55one value that you need
50:56for your code
50:57well perhaps now
50:59you can just put down
51:00your shovel
51:00and pick