 So let's talk about good object-oriented programming. Short, good. So my journey started during my studies. I learned C++ and then Java. Those were two first object-oriented languages that I learned. And it was really great. It was great because I learned about objects, and interfaces, and messages, and encapsulation. And I started learning programming during my study. So we started with some basics using languages like trubopascal or C. So when I learned object orientation, it was great because we started using classes. And we started using normal words, like person or a group. And we started working on projects with small teams. And we started discussing classes, and roles, and responsibilities. And it was just great. It felt really, really magical for me. Truth is that during my first years of studies, I wasn't even sure if I'm going to be a programmer. I thought that it's not for me. But once I saw object orientation, I was like, yeah, that's it. This is nice. I can do that. And then I got my first job. That was a bummer. But well, I was still a student, so it was cool. I got my first job. So OK. And I started working with code like that. If you've done any PHP, you've probably seen it. But I'm showing this to you because I was seeing functions, I was seeing functions everywhere. And after my studies, I wasn't even sure what functional programming is. Everybody was talking about object orientation. And I started using PHP, and I started seeing those functions and function and function and function. I was like, functional programming is ugly. It's just ugly. I want objects. I want classes because it's beautiful. I can organize my code into classes and objects and interfaces, and it's going to be great. And then I discovered that PHP has object-oriented features. So I was like, yes, I can do that. It's going to be awesome, right? So I started working with object-oriented PHP. And it took me about a year to say, well, it's great. But there are some issues like a lot of boilerplate, some very early PHP overams, very nasty, and inconsistency everywhere. So I was like, well, that's not good object-oriented design. I don't want to do that. So what choices I had? Java? Well, we already had this opinion. It was, I think, 2006. People were already talking about, well, Java, it's just nasty object-oriented language. Enterprisey, very bloated, abstract factory, factory, all those common jokes. So not good object-oriented design. I'm not going to do that. It's going to be boring. C++? Not really. I wasn't experienced enough, and it would be very hard to find Java as a C++ programmer. So I started looking for something that's better. So I started learning Python, and I kind of liked it. But then I was introduced to Ruby on Rails. And that was great. That was great, because after my experience with PHP, which I use mostly to build web applications, when I learned about Ruby on Rails, it was great because the boilerplate, I could just write very little code, and it would just work. And that was fantastic, especially when I've seen Active Record for the first time. I was like, wow, two lines of code, and so much functionality. This is it. Now I'm going to write great object-oriented code. I have great features, and it's going to be great. It's good object-oriented design, right? It's great because I can work with the data very easily because Active Record is very powerful. It has convenient interfaces, so I can just access my data, and then I can add some behavior, and it's going to be super awesome, because I have all those ridiculously powerful interfaces that are just there for me. I can use them. It's great. And then you know the story, probably. I think you do. Then we started seeing things like that, right? So repository Active Record object, right? It's from Gittori's project, by the way. It's a real thing. So I realized that, okay, so this is a data structure that's connected to a database. That's already pretty complicated. And then we use Mixins in Ruby for everything, and Mixins is just multiple inheritance, so what can go wrong? Well, we are adding more and more and more, and then we are defining 14 associations. So that's a lot of complexity. And then we add some behavior on top of it, so we end up with this, right? And you know, you've seen that, right? We've seen that. I mean, it's nothing new. We've been discussing that for five years, I think. So that's kind of boring. And I realized that that's not good object-oriented design either. I was like, okay, what's the reason for using object-oriented design? I want to use it because it's gonna help me with dealing with complexity, but it didn't work like that, at least not for me. So this talk is about blending functional and object-oriented programming in Ruby. It's probably not a typical Ruby talk, although I want to make one thing clear that it's not one of those talks where I was bored during the weekend and I decided to do some crazy stuff with Ruby, and now I'm like, yeah, I'm gonna talk about that because it's crazy and it's kind of cool. It's a bit different. This is based on fewer years of experience. I've been experimenting a lot with different styles of Ruby, and that's basically my conclusion. So my name is Piazzolica, as you've seen. You can find me on the internet. I'm typically known as Solnik. So I tried to blog about Ruby and open source projects on my blog, follow me on Twitter, find my stuff on GitHub. I've been working on a project called Ruby Object Mapper, and the things I'm gonna show you are pretty much taken from this project. They were born while we were working on this very project, so it's a pretty important project for me because of that. So my path to good object-oriented design leads through functional programming, and it was an accident. It's not like I've learned functional programming, and then I was like, now I want to write Haskell, but I will use Ruby syntax, or now I will write Elixir with Ruby syntax because this didn't work like that. I just started applying certain concepts to my code, and it turned out that they are functional, and then I started learning about functional languages, and I was like, wow, wow, it's the same thing. So that's interesting. So the first thing that I wanna talk about are functional objects. So functional objects have a lot of common concepts. They follow common conventions, or even rules, I should say. And the first rule is that they are immutable. And when I say immutable, I mean immutable, because in Ruby it's kind of difficult to have truly immutable objects. To have a truly immutable object in Ruby, you would have to deeply freeze it, which means that you're gonna have some code that is very, very slow. On a larger scale, it would be too slow. So there are gems that do that for you, but I stopped using them because of the performance issues. But they helped me to understand how to design my systems in a way where objects don't have to change. So the second thing is that the functional objects have common interface, which is method call. It's the only method, the primary interface, that is used to trigger some behavior of a given object. Now, I'm not saying that this is the only method that I implement. That would be kind of stupid, but there are many other methods that I can implement, but the primary method, the method that triggers the behavior is call. And it always receives an input, and it has no side effects. It means that if call method received a hash, it will not change it. Please don't change hashes that you receive. Don't assume that you own them because you don't. So no side effects also mean that the object itself will not change. So that's important. And they always return some output. And it's also important because when something receives an input and returns some output, you can continue with the processing. You can apply more and more functionality. So you probably notice that we're talking about objects that work like functions, which is pretty cool. So the first thing is to get rid of immutable objects. As I mentioned, immutability is the first rule, the first convention. And it's really important, and even though the implementation and the kind of technique that I use is very simple, the effect of applying this technique is pretty mind shifting. And it's a long process to actually understand how to design your system in a way that your objects won't have to change. Because it means that once you instantiated something, it must be ready because you will not be able to change it later on. So it must be ready to be used. And that's a big change. So immutability-oriented design is quite simple. So here's a class, or a typical class in Ruby, some user query. It receives some dependency. It's injected into the constructor, and then we call it, right? So it's typical to define interfaces that allow you to change an object, which means that when we use this object, we instantiate it with some query, then we call it, and then it's possible to change it. It's a very common thing to do in Ruby. And for many people, it's absolutely okay. It's even idiomatic. For me, it's very bad. When I seek out like this, I'm like, no, no, I wanna go. This is something that I cannot rely on because when something can change, some other thing might depend on it, on its initial state, and then the state will change, so the thing will break, which happens a lot. And this is the source of complexity and a source of bugs, so I stopped doing that. So this is the design that I prefer these days. And as you can see, it's a pretty simple concept. I still have a constructor that receives a dependency, and then I just return a new instance if I want some different context for this object. It's a very, very simple technique. Even though it's simple, applying that to your entire application is not simple, because we are used to the fact that things do change. We rely on the fact that something can be changed, and it means that we often instantiate an object which will change in order to be able to use it. So we need to do more work before we instantiate objects, and that part is difficult. So when we have this object, we just instantiate it just like we did before, then we call it, and then we just ask for a different query, and we call it again. And the cool part is that the initial object will not change, so we can safely, for example, store it in some registry and make other objects depend on it, and it will just work. So the second topic is what about the state? When I say state, I'm talking about data, you know, the attributes. We love attributes, right? We love to define attributes and define types and have coercion, and we love with objects that are bags of attributes. And that is already complex, but we typically add behavior to it. It's also a very typical object-oriented idea to have data combined with behavior. And now I'm gonna say something heretical because I prefer stateless objects. I prefer objects that only have behavior. They receive some input, some data, some state to the call method, but they don't include any kind of state. They don't encapsulate any kind of state, especially if it's mutable. So that's heretical. I mean, you're like, whoa, what? I mean, we have objects with state everywhere and it's object-oriented, right? Now it's okay. I mean, it might be surprising, but it's okay. So here's a typical class in Ruby. Let's say we wanna persist a person. So a typical thing to do is to pass the person to the constructor, assign it to the instance variable, and then have a method that will use some external dependency to save this person. Now there are a couple of problems here. So the first one is that we pass the state to the constructor, which means that we turn this object into a safe object which also has functionality which is persisting the person, which means that we coupled this object to a specific kind of person, which means that it's not flexible. It's not reusable because we can use it just once. And then we do a common mistake of coupling this object with a specific class. We didn't use dependency injection and that's just more coupling and it's also less flexible. So when we use this object, we can instantiate it with the hash for the sake of simplicity. And then we call it and then what? Then we can't do anything about it. It's just a throw away object because we use it once and we cannot reuse it anymore. And it's a problem because if we want to do something else with this person, it's not that simple because now it's the part of the internal state of this object. So composing more functionality, it's not that simple anymore. So the design that I prefer is to use constructor just for one thing and it's dependency injection. I'm no longer discussing things like what should go to the constructor. I decided to always use it just to inject the dependencies if there are any. So this means less coupling because this object is now coupled to the idea of user repository but not to a specific class and it simply uses its interface. So it's definitely less coupling. It's more flexible. And then we pass in the input to the call method which is nice because we can do this. We can instantiate the object. We can call it and we can use it many times. Now it's a small change. It's a small difference but it has big impact because we can instantiate objects just once and then reuse them many times. So the outcome of this design is that you separate the structures that your application is working with with the behavior which is kind of against object orientation. It means that suddenly all the data that you receive or extract from some database becomes something that's first class. It should be a concept in your application. It should be well-defined. And there are libraries that do that but it's like a separate subject for a separate talk. So I just want to mention that. The nice aspect of this design is that once you have those data structures you can easily add more functionality implemented inside small objects that will rely on those structures. And it's absolutely simple to do that. It's way simpler than having objects with state and then trying to figure out whether you should use inheritance or include a module or whatever because you just simply compose functionality together and the data structures are just passed in from one object to another. It simplifies your code. When you don't mutate anything and when you use immutable objects it's really simple to compose functionality. You have objects that don't change so you can safely rely on them. Nothing will break because nothing changes. So if you want to compose some more complicated functionality we can use a couple of objects and just call them like that. And it looks pretty much like calling functions, right? So the downside of it is that Ruby doesn't have any built-in interfaces for this kind of object composition. But it's okay, we can implement our own, right? So I'm gonna talk about a couple of functional interfaces that I implemented inside Ruby ObjectMapper and now they are being extracted into separate gems. I found them to be really powerful, surprisingly powerful. So the first one is out to curry. Sorry you were hungry, so. I forgot that you were hungry. That was a mistake, sorry. So out to curry is a simple idea. So let's say we have a class log event. It uses a logger to write some logs and it has an interface where the call method can receive a type and a payload. So we can use a small extension. It's called out to curry. It's not released yet but I will do that like tomorrow I think. It allows us to include a small extension and then say that the call method will be lazy. What it means is that we can create the instance of this object and then call this object with just the first argument and it's gonna be partially applied. Which means that we can call it again with the remaining argument and it's gonna work. Now I know it's weird, like what is this? That's confusing. Well, it's not that weird. In Haskell language, every function is lazy. You can partially apply arguments to any function. You can compose them and things will just work. So it's not a really crazy idea. It's something that is pretty fundamental in some languages. It's also a very small, I would say, lower level building block for some high level functionality that gives you a lot of flexibility. So the second thing is functional composition. I'm gonna show you one type of functional composition that I've been using in Ruby Object Mapper and I started using it in other projects as well. It's called pipeline. So if we have a class, an object that persists to user, we can add this thing and it's gonna add a pipeline operator. An idea is really simple. It means that if we have some other object that, as you've seen before, logs some events, we can create those objects and then we can do this. This means that we're composing a pipeline, which means that create user will persist the user and then the output of this operation will be passed to the log event. The log event is partially applied, which is cool because it will do what we expect it to do. We don't need extra classes. We don't need extra abstractions. It's a simple idea. And when you look at the implementation of this operator, it's actually pretty object-oriented because it's object composition under the hood. We have a left side and a right side and then we call the results from one side with the other one, so that's pretty simple. So yeah, that's also confusing, right? I mean, pipeline operator, what are you talking about? That's just crazy. But it turns out that in Elixir language, you have exactly the same thing. You have pipeline operator, which looks a bit different, but it's the same concept. You're composing some functionality from small pieces to get some more high-level concept back and then you can just use it. And it's extremely powerful. So what happens when we combine those techniques, those functional techniques, functional ideas, and some functional rules like immutability with object orientation? So first of all, when we start treating immutability as a virtue, as something that is actually beneficial, when we start having objects where mutation is just not possible or discouraged, at least, we have consistent and side-effectless interfaces and that leads to great composability. It turns out that you can implement a lot of functionality in very small objects and combine them however you want and it's very, very simple. Now, I've been spending quite a lot of time learning about all kinds of object-oriented rules and principles and code-smells and refactoring techniques and everything and over time I realized that I'm moving towards objects that are like functions, like singular responsibility principles, a great example, like if you start to follow this principle, you will end up with an object that is like a function, pretty much. And the nice part of this is that consistency allows you to do this and it's a really, really nice thing to have. And on top of it, with functional interfaces, you can build high-level object-oriented abstractions and that's like my latest discovery and I was really happy to see that because it turns out that to build some high-level, more object-oriented abstractions, when I have small functional components under the hood, things become so much simpler. So I'm gonna show one example. It's a library that I wrote, I think, a couple of weeks ago. It's called TransFlow. It's for composing business transactions. It means that when you have a bunch of things that need to happen inside a transaction, you can do that with a DSL. So it's very simple. You just define steps and it will execute first step and take the result from the first ones and do the next one until you get the final result, which I've shown you already, right? It's this thing, right? Under the hood it uses the simple concept of object composition just like function composition in functional programming languages. So it's the same thing under the hood. So the nice part was that I was able to add some additional features to that without much complexity. So I realized that I have some use cases where I would like to use publish, subscribe. So I added a feature called publish. It uses a jam called whisper under the hood which is really nice, check it out. And the idea is that each of the steps can publish some messages, some events. And then we can define an event listener. And then this event listener can have methods that will be triggered by a specific event. So we have persist step and we have persist success and of course persist failure. So this is a very common thing to do and I refactored a lot of really nasty code with this approach in my Rails app. But then it turned out that I have some use cases where I cannot use that because I have some information only inside controller and I cannot easily pass that to an event listener. It would be just too messy, it would be more complexity. So I realized that I can use some underlying pieces. So if we're using event listener, we subscribe it and then we call it. But what if in the moment of defining the transaction we have some information that we want to just pass in to some step. And it turned out that I can use the outer curry that I showed you. So we define the translator without publishing, we define the log event step as the last one and then we say, okay, log event should use the create user event type. And then we call it and things just worked. So this is built on top of functional interfaces and I didn't have to add any kind of additional abstractions. I just reused existing functionality and I was really, really happy to see that because under the hood it uses the same kind of stuff, just the pipeline and the partial application and we're calling the input and that's it. So what happens when we start treating functional programming as something that we can take inspiration from and combine them with object orientation? So it's kind of difficult to discuss it because this is the kind of feedback I typically get. So it seems like that would much rather be programming in a statically typed functional language. And yeah, that's true, right? I mean, my brain kind of shifted towards functional programming. That's pretty obvious. But the truth is that I program in Ruby and I'm gonna do that for quite a while and the things that I've discovered are really easy to implement in Ruby and they are not crazy. This is pretty simple stuff. And with all the things that we have in huge projects like Rails, which provides a ton of additional abstractions with a ton of complexity, I don't think that those simple functional concepts are more crazy than anything else that we already have in Ruby. So why not try it? Especially that I want to write the best Ruby that's possible. And for me, good functional programming combined with object orientation means good object-oriented design. And that's it. It's wow, it's great. Thank you.