We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Functional Data

00:00

Formale Metadaten

Titel
Functional Data
Serientitel
Anzahl der Teile
163
Autor
Lizenz
CC-Namensnennung - keine kommerzielle Nutzung - Weitergabe unter gleichen Bedingungen 3.0 Unported:
Sie dürfen das Werk bzw. den Inhalt zu jedem legalen und nicht-kommerziellen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen und das Werk bzw. diesen Inhalt auch in veränderter Form nur unter den Bedingungen dieser Lizenz weitergeben
Identifikatoren
Herausgeber
Erscheinungsjahr
Sprache

Inhaltliche Metadaten

Fachgebiet
Genre
Abstract
I have always said that Event Sourcing is "Functional Data Storage". In this talk we will try migrating to a idiomatic functional way of looking at Event Sourcing. Come and watch all the code disappear! By the time you leave you will never want an "Event Sourcing Framework (TM)" ever again!
Message-PassingInterface <Schaltung>OvalDokumentenserverStatistikEreignishorizontPhysikalisches SystemMustervergleichFunktionale ProgrammierspracheObjektorientierte ProgrammierspracheEreignishorizontZustandsgrößeFunktionalInterface <Schaltung>CodeMultiplikationsoperatorFramework <Informatik>Message-PassingOvalPhysikalisches SystemDokumentenserverOpen SourceVererbungshierarchieBusiness ObjectResamplingGanze FunktionLambda-KalkülKomponententestEndliche ModelltheorieDomain <Netzwerk>InformationsspeicherungProjektive EbenePerspektiveAggregatzustandFaltung <Mathematik>FunktionspunktmethodeDatenstrukturStreaming <Kommunikationstechnik>EntscheidungstheorieBildschirmmaskeKlasse <Mathematik>Objekt <Kategorie>Innerer PunktMusterspracheDivergente ReiheE-MailPlastikkarteTypentheorieCoprozessorÜberlagerung <Mathematik>Elektronische UnterschriftVariableRechter WinkelSchreiben <Datenverarbeitung>InstantiierungBitNichtlinearer OperatorDatenfeldMobiles InternetAlgebraisch abgeschlossener KörperCASE <Informatik>SystemverwaltungKonfigurationsraumBootstrap-AggregationTermFaktor <Algebra>VersionsverwaltungSichtenkonzeptDatenbankDreiecksfreier GraphFormale SpracheMailing-ListeSoftwareentwicklerSoftwaretestGeradeQuellcodeGruppenoperationParametersystemLoginMathematikGüte der AnpassungTransformation <Mathematik>Auflösung <Mathematik>RefactoringSpiegelung <Mathematik>Kartesische KoordinatenDienst <Informatik>InformationsüberlastungElektronische PublikationSoftwareEinfach zusammenhängender RaumMicrosoft dot netDatenverwaltungRandomisierungProxy ServerAbstraktionsebeneUmwandlungsenthalpieSpeicherabzugDifferenteÄquivalenzklasseLastSnake <Bildverarbeitung>RechenschieberMereologieMAPKonstruktor <Informatik>PROMWort <Informatik>HoaxStrömungsrichtungOrdnung <Mathematik>PunktPlotterGewicht <Ausgleichsrechnung>SystemaufrufProgrammfehlerInjektivitätFront-End <Software>RechenwerkQuick-SortPrinzip der gleichmäßigen BeschränktheitRichtungDatenflussMathematische LogikComputersicherheitDynamisches SystemSchnitt <Mathematik>NormalvektorCompilerProgrammbibliothekLesen <Datenverarbeitung>Hook <Programmierung>AutorisierungVarianzOffene MengeStrategisches SpielBenutzerschnittstellenverwaltungssystemProdukt <Mathematik>ZeichenketteRaum-ZeitZählenData DictionaryInformationVorzeichen <Mathematik>AppletWechselsprungVollständigkeitTuring-TestElektronischer ProgrammführerZweiComputerspielComputeranimation
Transkript: Englisch(automatisch erzeugt)
Okay guys, we're going to get started. What we're going to be looking at today is event source systems and how event source systems are actually not object-oriented. Most people today implement them with object-oriented code, but at their core they are not object-oriented.
They're actually functional. What's interesting is when you start getting in and you start looking at how they work in object-oriented code, you'll find that it obscures what's really happening underneath the covers. If you go through and implement it in a functional way, you'll find that your code will actually become more clear and it becomes completely obvious what's actually happening.
The place I want to start, because it's one of the biggest smells that you'll start finding in your object-oriented code, is actually a test. What we have here at the top, this test fixture, a specification of T of T command, I give people this code in class. It's basically a little test harness, a testing framework, that allows you to write specifications
that look like this one here, deactivating an inventory item. The great thing about these is you can also print out documentation from them. But when I go and I look at this setup, this setup, it's a bit bizarre.
It's really obscuring what's happening inside of this test. If I were to really start looking at this, what we're really doing here in a functional way is we actually have a pipeline. And we're saying that we have given, which pipes to when, which pipes to then.
But it's hard to recognize that when it's written in C-sharp code like this, with an object-oriented style. And there's all sorts of weird little broken things inside of this. So what we're going to do is we're going to start refactoring some object-oriented code, and we're going to take it into more of a functional direction. How many of you went to Jeremy's talk this morning? So we're not going to go really fast.
We're going to go very slowly and take small steps. And we're going to refactor little bits at a time without doing anything too scary. And we're going to move from having a completely object-oriented model to having a completely functional model. And at the end, it will be nicer to work with, it'll be easier to test,
and everything will be nice. So let's just jump right across. How many have seen one of these before? An application service. This is one way of implementing this. And this would be what I would call the idiomatic object-oriented way of doing things in terms of domain-driven design.
Nobody uses this pattern anymore. Everyone's basically moved to something known as a command handler as opposed to using an application service. Does anyone know why people have moved? So this is a really useful point cut in terms of software. There's one of these per use case on top of my domain model.
And there's lots of things that I would like to do per use case. As an example, security. How many have implemented security per use case to see if somebody's allowed to do something or not in terms of authorization? So how would I do that here? I'm guessing we'd probably end up with something like this,
where I'd come up here and I'd be like, requires permission, and we'll say admin. How many have done something like this before? You can admit it. It's okay. So, okay, cool. Now, how does that work?
Let me guess. You have a dynamic proxy that now is going to hook this? Have you ever tried explaining a dynamic proxy to a junior developer? Have you ever had a method that did something like inside of some code, you did something like this, and then wondered why the code stopped working?
Well, when I do that, I unwrap my proxy. Dynamic proxies are horrifically complicated. By the way, if you have a bug in production, does your boss care whether that was your code or whether that was some open source project's code that caused the bug? Or is it still your bug?
When you bring something into your project like a dynamic proxy, this is a vast dependency, and there's lots of opportunities for bugs inside of it. So I prefer not to use something like that. But at the end of the day, we have to ask what question was it helping with? What does a dynamic proxy do?
And it will become more apparent if I make a second one of these. And what I'm going to do here is I'm going to grab this. I'm going to copy and paste it. We can imagine what the rest of the structure would look like, but we might have another one of these, which is reactivate. And it takes an id, it takes an int, which is a count, and it takes a string, which is...
Let's not make this a string. Let's make this a user just to make it more fun. We'll say it's a user user. Okay, so how do you do a proxy pattern on a method named deactivate of guid of string and on a method reactivate of guid of int of user?
How do you write one proxy that will hit both of those methods? And the problem is you can't. This is the exact problem that a dynamic proxy solves. It allows you to hook a method of arbitrary name with arbitrary parameters of arbitrary type and to give you a common interface across them.
This is why your dynamic proxy, when it calls you, it passes you back. Here's a method info, and here's an object array of the parameters that were being passed to that method. Of course, and it's going to be a theme we're going to look at quite a bit today, what if I were to just decide I'm never going to have that problem? And I were to say that we're only ever going to have a single parameter
that goes to this method. You could then make a common interface for that, right? So let's try it. Now, I am using, obviously, some of the best refactoring tools in the world here. It's called Sublime. If you happen to use something better like ReSharper or IntelliJ, there's actually a refactor for this. It's called Refactor Parameters to Object.
So what I'm going to do is I'm going to use my neat refactoring tools, and I'm going to say this is going to take a deactivate, which is going to be D. Then we're going to have a public class, deactivate. And what we're going to do here is we're going to pass these. And for right now, I'm just going to make these publics.
I would probably do something a little bit better than this if I were actually building a real system. So, okay, now we're going to have these. And, of course, we're going to have to come up here, and we would do like a D.reason, and this would be a D.id. Okay, how many of you think that was a hard refactor?
I just changed everything, right? Well, but what it allows me to do is I can now have a common interface. So now what I'm going to have is an interface which has a handles of T. We can say where T is a message, and we'll add that marker interface in just a second.
Now I'm going to have void handle, which takes a T, which is my message. And let's just put in our marker interface really quick. So now we've got an interface that's going to be called message. And here what we're going to have is this is going to be a message.
Okay, so now my deactivate inventory item application service, his name's going to change. He's now going to be called a handler. And this is a handles of deactivate. And, of course, we'll have to rename it down here too. So we'll just call this a handler now.
Okay, again, how many of you think this was a hard refactor that we've done? I mean, we're just playing with things a little bit. We said we're going to pass an object as opposed to passing a group of parameters. But you now have a common interface across all of your application services, all of them.
And what this allows me to do is I can now do basic composition across these. Instead of using something like a fancy tool, I could say, for instance, we're going to have a public class. It's going to be a logging handler of T, which is a handles of T. It's going to have a private handles of T, which is going to be underscore next.
Then we're going to have a public logging handler. And this is going to take a handles of T, which is the next. And don't you love how often you repeat yourself in C sharp?
And then we're going to say underscore next equals next. And then what we're going to do is in our handler here, we're going to have a public void handle. This is going to take a T, which is our message. And then we might say, for instance, something like my super amazing logging framework that our devs built in house dot log message.
And then I could say, for instance, underscore next dot handle message. Cool, we've discovered the proxy pattern. But now I've got a common interface, so I can make this work across all of my handlers.
Easy enough. But this interface, handles of T, how many of you work in dot net today? And I know in Java 8 they have this new thing called lambdas that don't support closures, which is an interesting idea.
But I'm going to give you a hint. If you are in dot net code and you see an interface that only has one method on it, I want you to ask yourself a question. Does it make any sense at all that I would ever add another method to this interface? If the answer is no, then why are you using an interface?
There's this other form of doing interfaces. It's called functions. And I'm reminded of Scott's talk last year. He had this brilliant slide where it was object oriented patterns functional equivalent. So it's like proxy pattern, function, repository, function. And the entire functional side was just functions. That's all that was on there.
And this is still idiomatic object oriented. So what if we were to try that? We've got this interface, it's handles of T. Why don't we just stop doing it that way and stop using these stupid object things? And instead what we're going to do is we're going to try doing it in a functional way. So in order to do it in a functional way, let's start with, I don't know, maybe a function. That sounds like a good place.
What do you think, Scott? Most of the patterns seem to start there. OK, so now we've got this thing called deactivate. Except now I would make this static because it doesn't need to live in a class anymore. OK, so my problem is before I had my constructor here and my constructor, it had parameters and stuff that I needed because I have dependencies.
How many of you use container today? OK, now keep your hands up. How many of you use almost exclusively constructor injection? Why? Because the container makes it easy. Have you ever stopped and thought about what the granularity of those dependencies were?
Do they actually match the life cycle of your object? How many have constructor injected something to only use it in one method call? So you've got 20 methods in the class, you only use it inside of one method, but you put it in the constructor. So I learned another way of doing dependencies.
It's been around for a while. It got popular in Fortran to start with. It's called passing parameters to a function. So now I've got my dependencies that are being passed in to deactivate. By the way, how many of you think this is scary compared to a constructor? Still relatively simple? OK, so cool.
Now what we're going to do is we're going to have another little refactor here. And I've got a bit of a problem. You see, right now I've lost my common interface again, haven't I? Because now I can have reactivate, and reactivate takes an inventory item repository, it takes a, I don't know, a reactivate credit card charger,
and then it takes a reactivate command. Well, we could do the same thing that we did before, right? I can just refactor dependencies to dependency object, and then all my functions will take a dependency object and a command. No, that's a bad way of doing things.
So basically what my problem here is, and normally I would not use an action of anything in a functional language. I would use a func of unit. Or if you go on my GitHub, there's an entire library for this. It's called Nothing. And if you really want to have some fun, read the comments. Some of them are priceless in the issues. Don's sign commenting on it is just hilarious.
So what I have here, and I'm just going to tell it as an action, but normally it would be a func of unit. So I've got an action of I inventory item repository of I can look up license of deactivate.
And you see what I want is I want an action of deactivate. Why do I want that? Because then I'd be back to a common interface, right? It'd be an action of T where T is a message, just like my handles of T. So the question is how do I convert from this into this?
And I hate to use the word pattern. It's more like a strategy. You'll notice in functional programming there's not really many patterns. But it's called partial application. So what I'm going to do now is I'm going to say I've got var handler equals one of the scary lambda expressions.
Then we're going to say deactivate with a new Oracle repository. To be fair, I really should call this that can't find TNS names because that's what always happens when you do that. And we're going to pass a new California lookup service.
Then we're going to pass in e. And what this is doing is this is taking a function that has three parameters and converting it to a function that now has one parameter by closing out two of the arguments. And as we take a more general function, we close out the arguments,
we return a more specific function. Let's just try another example of this really, really quickly. So let's give us some room here. So I'm going to have an int add. It takes an int x, and it takes an int y, and it will return x plus y. And how many less characters would I have typed if I did that in F sharp?
It'd be so much easier. So now what I'm going to have is I'm going to say we've got var add six equals, again, one of those scary lambda expressions. And we're going to say add x to six. So now add six is a function that always adds six. And this is the same thing that we're doing here with our function up here.
But now I want to change that a little bit really quick. So let's just get rid of this. And I'm just going to talk about a thing. It's going to be called handlers. And what handlers is is handlers is just a dictionary of type back to handles of type. And you can imagine, like, when I receive a message, I need to look up the handler for it.
So I look it up in this dictionary. So let's just put some spaces here. And let's copy and paste this a couple times. Maybe with the spaces would be better. OK. So what are some other things you might want to do with some inventory here? Let's see. We said that we're going to have another one here that was reactivate.
We got another one of these. How about a check in? We might have another one of these, which is, I don't know, check out seems reasonable. And then we might have another one of these, which is going to be audit. OK, cool. Now, when you go through and you build a service, how many methods do you normally have in it that are public?
Is it like five or 10, or is it like 33,000? And remember, I've got one of these methods per use case in my system. Now, how many of you are using a container again? Just keep your hands up. OK, cool. So I know another way of working with something like a container.
So what we're going to do here is we're going to say we've got a method that's going to be called bootstrap. And what we're going to do inside of bootstrap is we're just going to call all these handlers. And I know that this doesn't have nearly enough XML configuration shipped with it. I was actually here with a team in Oslo.
I will protect the guilty. And when I went in, they had more XML than they had Java code. They had like nine megabytes of XML configuration. Why? Because everything needed to be runtime configurable. And if you went and read their XML, it had things inside of it like field names.
How many admins do you know know the field names of your objects? The internal field names. So how many times do you think this had been edited by admins? Never. But it was runtime configurable by developers who would do that and then run it through a testing cycle. And they managed to convince me that XML is in fact a Turing complete language.
But what's so awful if I were to do this? I mean, to be fair, at the end of the day, I'm going to end up with the same amount of code there that you basically have to configure containers just like I'm doing it by myself. And I will have people, they'll be like, oh, no, you can't do that,
because, see, you're just doing singletons. Everything there is a singleton lifestyle. What happens if I need a repository per request? And it's like, well, OK. There you go. That's also known as a factory pattern, or as Scott would point out, a function. Do you want a custom lifecycle? Well, you can pass a custom function.
And this is an easy way of doing things. And now I'm not telling you guys to get rid of your containers. In fact, you can even make this runtime configurable if you want to. Great way of doing it? What if I were to ship a file with my software? It's called bootstrap.cs. When my application starts, I compile that code and run it.
You want to edit me? Go edit the code. And then you also get IntelliSense and all that other kinds of good stuff. Whole type system to back things up, make sure you're not screwing things up. You can do this, and it works reasonably well. I can even do the same kinds of things that we were looking at earlier with our logging handler.
So for instance, I could say that we've got a public void log of T. This is going to take a, what, it's going to be an action of T, which will be our next. And it's going to take a T, which is our message. And here we would say, like, logging framework.log.
And we're going to pass our message. And then what we might say is something along the lines of next message. And then I could basically compose any of these methods by wrapping log of T around it. Now you have a logging handler that also does something else. Relatively simple. It's also known as a pipeline. If you go use F sharp, it won't look nearly as disgusting because you have a pipe operator.
Once you have at least three of these, it just gets really, really nasty to read. But in F sharp, no problem. So, okay, now we know we can compose. And I've had lots of people tell me, but, you know, still it's not as good as my container because, you know, what happens if I come in this code and then I'm like,
we need a new Oracle connection factory, factory, which takes a new TNS names random selector, which takes a new TCP abstraction, which takes a new connection manager.
You know what? As you're typing this, I don't want to help you with this problem. I want you to type all of that, and I want you to think, I'm an idiot, what am I doing on every single keystroke? Just stop. There's no reason why you need seven levels of nested dependencies for a repository.
There's just absolutely no need. And when you're working in this kind of code, helping you do this will actually hurt you. If I'm going through and I'm building the new version of WPF, yes, I will actually have seven levels of nested dependencies because that's a real problem, and it's what I should have. In this code, you don't need it. And there's very little benefit that you'll get by having it.
So, okay, now we've moved to a more functional style. We're now using some functional composition. Let's go back and let's take a look at our test again. Here we create a new T, and then I get my events, which come from given, and I pass them to my subject under test
and tell him to load from his history for an event source system. And then I say on handler, which gives me my command handler, and I call handle, and then I call when, which will actually give me a command. And then I do this really derpy shit where I say produced equals new list of event of set get uncommitted changes to pull those out of the object.
This is just a whole bunch of weird steps along the way. So the whole problem with this, and then we'll also need to have a fake repository so that basically when I go to save, I can then pull them out of the fake repository. The whole problem with this is relatively simple.
Everything that's in there comes from that line of code. So in order for me to test now is hard because I say repository.save, and I put something in there. So instead what I'm going to do is I'm going to pass across a fake now, and basically what I'm doing is I'm hooking through the fake in order to get the data that was saved to the fake so I can pull it back out and I can insert off of it.
I know another way of doing this. So instead of doing that, what we're going to do here is we're going to say that this is an IEnumerable of event. And what if here we were actually just to return item.uncommittedChanges?
How would you test this code now? Would you need a fake repository to jam this stuff around to pull out and get the events off the back end, or would you just insert off the return value? Once we start moving to a more functional style, normally you will not have a void method for your command handling.
It's going to return a series of events. And then what do you do with them? Well, you may decide that you want to save them, and that happens to level up. This will make your code far more testable. By the way, when I did this bootstrap method, did my code become any less testable because I did that instead of using a container?
Is my function here deactivate? Is this any less testable than when I was down here and I was dealing with the command handler? It's just a different way of expressing the same thing. And all that we're doing here is we're refactoring very, very slowly away from object-oriented code back to functional code.
And it's not that one is right and the other is wrong. They're two different idiomatic ways of doing things. By the way, if you were using F sharp, you would not use handlers.add here. You would just put in a thing called a pattern match. And I wouldn't use a type in a dictionary. Instead, I would take a pattern match and basically call the method, and I'd just do it in code.
But we still have this object thing here inside of our domain model. And to really understand this, it's probably best that we actually jump in and take a look at what that thing may look like. And I've been showing people this code for over five years now. And this is a simple little domain object.
Now, the general idea when you start following event sourcing is you end up with two methods to do any kind of behavior. The first one is a public behavior, deactivate. The second one is a private method that's called apply. And the general flow that we have through here is what I call deactivate, it may do some business logic.
And when it's done doing that, then what's going to happen is it calls apply change. This gets hooked in a base class. It will add the change to a thing called changes, and it will hold it. Relatively simple.
Later, when I want to get the events out, I basically call get uncommitted changes. You can actually see where that happens here in the repository. We call get uncommitted changes. But this is like a whole bunch of mutable state, and we're not really buying anything for this.
And there's other ways of doing it. So I'm curious. Can anybody tell me what the parameters to this method are? It depends? The events. Well, it takes one event, an inventory item deactivated.
Does it have any other parameters? This, yes. There's actually a hidden parameter here. He's hiding. We don't like to talk about him. C sharp compiler talks about him a lot. And it's actually, if I wanted to do it properly, it would be inventory item this.
And he returns void because he mutates. Now, another way I could do this, just as a simple thing, I could say, you know what, we're actually going to make him return an inventory item. Why? Because we don't want to mutate stuff. I don't ever want to mutate. So I'm just going to return a new version of an inventory item that has the one change that I want.
So I take an inventory item and an event, and I return a new inventory item that has that event applied to it. How many have heard that immutability is amazing? All I've done is I just said I'm not going to mutate my domain object. We're still just returning a normal domain object. It's just now an immutable domain object as opposed to an immutable domain object.
And then what I would end up with is I would basically call all my applies here. And basically I would chain them. One apply to the next apply based on the event. And, you know, we can go look down here, and we can see the way this is going to work is I call this get events for aggregate, and I call load from history. And then what that does is it uses this thing as dynamic
because you need dynamics in your code or else it's not cool. To be fair, that is actually here. This may be too small for you guys to see. There's a file here that's actually called infrastructure crap. Don't bother reading. It's not important. Anyone want to guess what the first file all developers open is?
But basically it takes myself as a dynamic and basically allows me to call private methods in my derived class because that's certainly a good thing to be doing. And so what will happen is when it gets an inventory and I'm created, it will call this method apply. When it gets an inventory and I'm deactivated,
it will call this method apply. But it's obscuring what's going on here. What I really have here is I have a pattern match based on type. Now, I'm implementing that through dynamics with magical private reflection, which somehow picks out private methods in my derived class. Probably not the best way of doing it, but it's cool at the time. But what I'm really doing here is I'm just doing a pattern match
based on the type of event that I have to figure out which method to call. And what we could do is we could do this explicitly if we want it. And if I go look at a series of events, so all of these, like down here, I've got this apply of inventory item with inventory and deactivated.
This is going to become the pattern that I use. So basically what we can say is that for any given event handler, we basically have f of state event. And what this returns is state. All we're going to do is instead of putting all my methods inside of inventory item and then returning an inventory item every time,
I'm just going to say, you know what, we're going to use a struct as opposed to using a class. And it won't be an object. It's just a piece of state that goes through an operation. And let's just grab some more room here. So now we can imagine that I've got some events that are happening. So like, for instance, we have an inventory item.
Let's type that right. And I'm just going to shorten these so I don't have to type them all. So we're going to do created. And after created, we have checked in, and then we have checked in. And now what we're going to have is checked out.
And then we're going to have deactivated. Now, if my functions up here were all of this signature where they take my current state and an event and they return current state, well, then I would have something that looked like this in terms of function calls. So first thing we're going to have is created, right?
So what's the state that gets passed when I've never had one before? I would accept state.empty or null, or maybe we have a little function called initState. And then we'll say that it gets passed the event. Then I have checked in.
And checked in gets the return value of created, which gets passed the initial state plus an event. And then we have checked in, which gets the return value of checked in, which gets the return value of created, and then it gets its event. And then we have checked out,
which gets passed the return value of checked in, which gets passed the return value of checked in, which gets passed the return value of created, which gets passed init for its initial state. And then we have deactivated, which gets passed the return value of checked out, which gets passed the return value of checked in, which gets passed the return value of checked in, which gets the return value of created, which gets the return value of initState. And e.
Oh, that was a lot to say. But let's just edit this a little bit, just see if we can make it a little bit nicer here because that's a really ugly line of code. Now, let's get it like this. Oh, there we go. That's much better.
So then what I'm going to do is I'm going to grab these. Has anybody seen a pattern that looks like that before? It's a higher order function. It's also known as a left fold. So how do we do this in functional version
of event sourcing? Well, we left fold a pattern match over the events, and that's how we actually get back our current state. Now, this is the exact same thing that we're doing in the object oriented code. It's just now we're being explicit, and we're just going to pass the pattern match to a left fold.
And we transform state along the way. What about unit testing? Has this become harder to test? So if I were to have a method here, let's make it a public state, apply, which is going to take a state, and it takes my event.
And in here, we can imagine doing something like return new state. And here, we'll say, I don't know, foo is equal to event.foo. How hard would it be to test that method?
It's a basic transformation. Given this state and this event, you produce this state. This code becomes trivial to test, absolutely trivial. And this is where we start going in terms of our domain model when we start working with functional based systems.
And what you end up with is a few core things. The first one is this function of state to event that returns a state. We have another one, though. It's function of state to command. Remember our command handling?
What does this return? Events. Now, for any given behavior that I do, I get my current state by doing a fold with the first method that we have there. Now, that gives me back my current state. I pass that state plus the command to the other function,
which returns me a series of events. Seem reasonable enough so far? By the way, wouldn't pipeline operators be awesome for this? And then what I do is I append those events, and they basically become part of my state for the next operation because I'm going to fold over all my previous events.
By the way, how many of you have seen this cute little guy here, this little dragon? Do you know why he's there? His name's Oro, which is short for Ouroboros. And Ouroboros is a snake or dragon that's eating his own tail. Does this sound familiar and like a dragon
that's eating his own tail? I come, I replay my events through the first function there that returns me back my state, which gets passed to the next function, which I give it a command. It gives me back a series of events, which I then append back to the first function, which brings me back to my current state.
In other words, my event keeps getting bigger and bigger and bigger in my series, and I just keep eating back off the end of my own tail. And when you start looking down into getting into more functional code, this is how we actually do stuff with functional event source systems. For me, I've always preferred doing it this way. And the reason I prefer doing it this way is, one,
it's more testable. How many have had a bug in a domain object due to mutation? I'm not going to say you're going to have less bugs, but I'm going to say you're more likely to have less bugs than more bugs once you start going to completely immutable models. I also prefer it because when I go read the code
and this is how it's working, for me, this is far clearer than what we were looking at earlier when we started getting in and we started looking at this specification as an example, or with the as dynamic calling private methods in my derived class, which, by the way, never do that.
That's just a really bad idea, but it was really cool in terms that it allowed us to have one line of code that did it. To be fair, if people don't know the simple CQRS example, it's actually called M-R, and that's because Norwegian A character apparently GitHub doesn't like. It was actually Mor was the original name of it.
And it was written in the Scotsman pub over on Carl Johan. For me, I find we can make stuff work doing stuff like this, but it really loses what's happening underneath the covers. Whereas when we look at it from a functional point of view,
everything makes perfect sense. And when I go read the code that's doing the fold over with a series of events and it's producing back a piece of state, this is very, very clear. If you've been to a talk where I talked about event sourcing before, I normally give the one sentence version of event sourcing for people that have
written functional code before. And that is current state is a left fold over previous behaviors. If you haven't done functional programming before, I also have a 20 minute discussion if you want to go through it. When people start talking about snapshots, and I know snapshots are the most important thing ever. What is a snapshot?
A snapshot is a memoization of the fold, nothing more. When we get into event sourcing, event sourcing makes so much more sense when we look at it from a functional perspective. Now, everything we've been looking at, you can even go play with today. How many have seen event store?
Has anybody looked at the projections model? Remember, we're talking about this whole left fold with pattern matching. So this is how it actually works. And you can do this not just for your domain model. Your domain model is a form of projection. It's coming back with a piece of state you're going to make a decision off of, whether it's a domain object or a piece of structure.
Any time that you take an event stream and you come up with state from it, it's a concept known as a projection. And projections are always replayable. There's another thing you can do. It's called a processor and that's not replayable because you'd be really pissed if you went to go replay this thing and I recharge your credit card because you bought something two years ago. Or my personal favorite one,
someone built a projection that was sending emails and then they replayed it. By the way, who's the first person that's going to email? The oldest one, that makes it even worse. So what we have in event store is basically the same thing we've been looking at. So remember, when I deal with a projection,
basically all of our functions are function of state event and this goes back and it gives you state. Now, if we look at a JavaScript projection, because JavaScript is my favorite functional language, I might say here that we have deactivated.
Remember I said we need a pattern match and well, this is one way of doing a pattern match in JSON. And here we would have a function. Remember, it's going to take state event, right? Now here we might say return new s
and basically what we're going to put in here, let's just do this. I hope we say s.id e.return id colon s.id and then we're going to say activated is going to be false.
Now we may have another one of these in here. How about we do a created, just that we have something more interesting to show. And here we say that we've got our created and here we might say that activated equals true and our id here is going to be e.id. And all we're doing is the exact same thing
we were just looking at with our domain model. I'm defining a pattern match and basically what we're going to do is then we fold this pattern match over a stream. Now, how many of you have used JavaScript before? What happens when I have like five to seven fields on that state that I want to move back
and I have to create a new one every single time? That gets really annoying, right? Okay, so we allow you to do something in V8 but it's a little bit scary. We allow you to write code that mutates but then we make it immutable for you. Come on, that's pretty scary.
So you can actually come in here and instead of doing all this, what you can actually type is instead of that you can just say like s.id equals e.id and that will work. And we will make that immutable underneath the covers for you without telling you about it. In fact, you can even go through and you can define global variables and we'll make your global variables immutable too
without telling you about it. Some really scary stuff. But it lets you write code the way that you want to write it, not the way we force you to write it. But this is exactly the same thing we were talking about where a projection is just a left fold of a pattern match. And to type that you would basically just say when
and you pass in your pattern match. Now the next thing that's going to be needed on top of this is some way of putting events into that thing. And we could, for instance, say we've got, I don't know, how about from stream foo. And what this says is take all the events
from the stream foo and then pass it to a fold of this pattern match. And that's the exact same way you would do it if you're working in F sharp, if you're working in Clojure, it's the exact same way that you do it. I may express the pattern match in a different way but it's the same pattern that you're going to be using.
We have other operations as well. For instance, you can say from streams, foo one, foo two, and let's do, I don't know, foo three because no one would ever guess that one would be next. And what this says is take these three streams,
join them together and then pass them through the fold of this pattern match. When we're talking about this kind of stuff, this stuff is inherently functional. How many of you have seen an event source system before? So I want you guys to keep this in your mind, okay? Well, let's go take a look at doing a projection
in the idiomatic object oriented way of doing things. So here we have our inventory list view. And you'll notice it's a handles of inventory item created, it's a handles of inventory item renamed, it's a handles of inventory item deactivated. And basically what it's doing here is it's updating something known as bullshit database, which I could have sworn was called MongoDB,
but hey, it's just as durable. But when you see this, what you see is an object with a series of handlers. And what happens is there's code on the outside that basically receives the event stream.
And what it does is it takes this object, it casts it to a handles of whatever that event type is, and then it calls based on the event type and gets overload resolution. Now, if you were to read this, how many of you would realize that's actually a left fold? It's not a left fold.
It is underneath, but it doesn't feel like it because you can't see this anywhere. It's happening off in magic reflections land with operator overloading to do a pattern match. What about when we do it this way? How many of you can figure out that that's actually really doing a left fold?
And this is why I prefer doing things in a functional way. When you do it in a functional way, it becomes totally 100% apparent what's actually going on. And if you guys want to see a full example of this, Jeremy has on GitHub with F sharp. He basically took simple C++ and just rewrote it with F sharp. And you know what? All the code disappeared.
It's basically one file afterwards. Whereas when I go look at the original, you know, we've got all these files coming down here, lots of different classes and objects, and here's ended up being like 70 lines of code to do the exact same thing. And at the end of the day, it's clearer what's actually happening compared to when you go look at the object oriented version.
For me, the object oriented version, it obscures what's actually happening underneath. Whereas the idiomatic functional way, it makes it really, really clear. And the beautiful thing when you get to it, instead of having code that starts looking like this, where you end up with a specification of T
with all kinds of weird stuff happening down in your setup, what you end up with is code that looks like that. And everything has become pipelines. Everything in our code is now basically just a pipeline. You'll find once you start working with things this way, you'll understand more what's going on
inside of your code. Your code will become shorter. It'll become more concise. And to be fair, it's probably gonna become more testable. Although if you can't write good tests in object oriented code, you're probably not gonna write good tests in functional code either. But for me, the big part isn't even the fact that the functional languages are cool and popular.
For me, the big part of dealing with this is when I go look at this from a functional perspective, the mental model hits exactly, and there's none of this obscure stuff going on. And to be fair, why would I need a CQRS framework for doing this or an event sourcing framework?
We've basically written all the code associated with this in less than an hour. If you go grab Jeremy's, his example, he's basically got the entirety of the framework already there for you. You know what? It's like 20 lines of code, the entire framework. And if you get to the point where you got a 20 line of code framework, what's the point of having a framework
unless you're in JavaScript? In which case there needs to be a framework. So with that, I will thank you guys for coming. I hope you got to learn something as we go through and actually just do small refactors to this code as opposed to making it something big and different and scary. Just taking small little steps
and refactoring towards a functional version. And if anyone has any questions, I know we're in Norway, so this is unlikely, but if anybody has any questions, I think we've got like about seven, eight minutes left.
Well, I did say it was Norway. Okay, well then again, I will thank you guys for coming. I do hope everyone got to learn a little something. And I'm doing a talk in the next session, and it's actually a new tool for F sharp and it's actually pretty cool, you should come. But thanks guys.