 Thanks for coming to my session. The topic of my talk is an algebraic approach to functional domain modeling. I start with the discussion of domain models, what they are because often I find that there is a confusion among programmers regarding what exactly constitute the domain model. Does it belong to the problem domain or it belongs to the solution domain. So I start with what are domain models and how we realize them as part of our solution architecture. The focus of this presentation will be on how domain models evolve in the solution architecture as piecewise composition of purely functional components. The focus will be on pure functional programming. I am not going to introduce any object oriented techniques here though in reality you will find most of the domain models being implemented using object oriented techniques. I will use pure functional components and compose those components to build larger ones which will model larger domain behaviors. This composition can be algebraic. I will define what I mean by a domain algebra and discuss how we can use algebraic techniques to build larger domain behaviors out of smaller ones. So domain modeling, actually functional domain modeling. What exactly is a domain model? This definition is from Wikipedia and I actually like this definition a lot since it highlights the defining aspect of what a domain model is that it is related to the problem domain and how the artifacts in the problem domain interact there to produce the correct domain behavior. When we refer to the artifacts for domain model we refer to the artifacts as they are in the problem domain and as a solution architect it's our responsible to map them to appropriate abstractions in the solution architecture. So you are telling I will be using the functional programming patterns, functional lengths as I call it and I will take some sample use cases from the real world the ones I have actually implemented and will transform the domain model into functional patterns into functional artifacts using the principles of functional programming. So there are two aspects to this. The first one is to build larger domain behaviors out of smaller ones. This is what exactly we want to do and the next part is how we want to do this. We want to use function composition as the secret sauce and by function composition we mean functions composed when the algebra of types align. I will be using a statically typed functional programming language Scala and I will be relying solely on the algebra of types to demonstrate how we can have functional composition to build larger domain behaviors out of smaller ones. Quite some time back Marius Eriksson of Twitter wrote this paper, your server is a function. What he meant is that all the bunch of servers that Twitter wrote those those which delivered services he distilled the architecture of all the Twitter servers into three separate abstractions. It's mentioned here those are the services, the filters and the futures and these are the abstractions which happen to align beautifully with the style of functional programming. They compose algebraically and he mentions that these three abstractions gave them the substrate for building reactive servers. Very recently he wrote one other article where he mentioned about the same three abstractions, same three functional patterns with which he demonstrates how they built large scale servers in Twitter using the principles of functional programming. Higher order functions, this article explores three specific abstractions that follow the style of functional programming, future services and filters. So if Twitter, Twitter delivers a bunch of services and the Twitter engineers can model them as a function or a bunch of functions, can we model our domain model as a function? Possibly an unrealistic oversimplification, can we model them as a collection of functions? For some simpler domain models possibly we can, but in the real world a proper domain model consists of a collection of smaller simpler domain models each of which we call as bounded context in the parlance of domain driven design. So one domain model is composed of a bunch of bounded context and the entities you define the value objects you design, the artifacts you define and the domain behaviors you implement, all of them apply to one specific bounded context. You cannot have entities spanning multiple bounded context, you cannot have domain behaviors that span multiple bounded context. So bounded context we call it as a specific unit and the domain vocabulary which each individual domain model has applies only to a specific bounded context. Later we will see that the bounded context is our unit of an algebra. So this part is clear, right? One domain model can be thought of as a collection of multiple bounded context. So loosely in terms of mathematics we can define it like this. A domain model can be considered as a union of multiple bounded context and what is a bounded context? A bounded context is a set of coherent modules. So we can define a bounded context as a set of modules parameterized on a set of types. Each module does a specific use case, each module does some specific collection of domain behaviors pertinent to the bounded context itself. And what is a module? A module is a collection of domain functions subject to a list of business rules which we call the predicates. The predicates of the business rules which need to be satisfied when we can say that the function works correctly or it returns the specific error that it is supposed to do when a business rule is violated. So fx is a domain function based on an object of type x. There can be multiple types and the important part is that each of these functions compose with other functions. That means it is closed under composition. When you compose two domain functions you get another domain function which belongs to the same module which belongs to the same domain. So this is how you evolve smaller domain behaviors into larger ones. So in summary we have the functions or morphisms as we say in category theory. We have the types which are modeled as sets, composition of functions and some rules or laws which are the business rules which need to be honored. And all of these together we call as domain algebra, as the algebra. So now if we go back to our definition of domain model algebra and algebra is composed of a set of types, functions and laws. We want to make these types explicit. Why do we want to make this explicit? Because we want to encode. We want to encode quite a bit of domain logic as part of the declared types, as part of the user defined data types that we will be defining. We can have type constraints which will once again encode some amount of business logic as we will see shortly. And the third most important point is that you can compose this algebra in terms of already existing algebra. In functional programming libraries you will find lots of algebra existing like monads and monoids. Those are all algebra which you can use as part of your own domain algebra to make your algebra richer. Instead of reinventing the wheel, if you reuse those algebras, in that case you get verification for free. Because those are algebras which have certain number of laws and those laws have been verified. So once you can incorporate those as part of your domain model, you get those verification also for free, verifiable. This is the next part. When you encode something in terms of types, if you can define the laws of the types, in that case you have a verifiable algebra. If you happen to use a dependently typed language like Idris, then you can encode more of business logic as part of your type system. And for those properties which you cannot encode as part of your types, you can define algebraic property based testing rules for that. You can define business rules properties and there are libraries using which you can encode those properties, generate random data and do an exhaustive amount of testing which you can never achieve by going for manual testing. So let us consider an example, problem domain. A problem domain from the financial markets, we will consider securities, trades, executions as they happen in the stock exchange. We consider some entities, account customer trade bank, these are some sample entities, some sample operations which we will model as domain behaviors. Note we are still in the problem domain. These are entities, those are vocabularies right from the problem domain itself. We have not yet modeled anything in the solution architecture part of it and we have some laws. Stock market has some laws, trading has some laws which we need to honor if our domain model needs to be a successful one. Now we try to map these into the solution domain. The domain behaviors can be straight way mapped into functions from types to types. The domain entities, these can usually be mapped to some algebraic data types. Once again we call them algebraic data types because they honor some algebra and we can do some algebraic manipulation using those data types. And we have some business rules or invariance to model the laws. These invariance can be modeled either as part of the type system as I was telling or we can write property based testing rules which will verify the properties once we run them. And these are some examples of existing algebra, monoid, monads and those which we will ultimately incorporate into our model to make the domain algebra of our model richer. And together this entire thing forms our domain algebra. Now let us get back to the earlier slide which we saw. So now we can replace this bounded context by domain algebra. So this makes it clear that the bounded context is the unit of our domain algebra. Now let us look at a sample use case. This is from a real world use case, real world system, simplified, but the basic concepts will be clear. Let us consider a sequence of actions which typically take place in the day of a broker. Some client places some order. It can be in any format because various clients, some clients send Excel, some clients send text files. So next we transform them to our internal domain model entities and place for execution. We need to transform the flexible formatted orders into some of our internal domain model entities or value objects. And once we have done the transformation, we place it for an execution in the market. The orders will be executed in the market and will result in trades and allocations. Trades will be generated and they will be allocated to specific client accounts. So this is a very simplified version of a trade being generated from client orders. Now let us try some functions to model the three sequence of actions. Client orders, it is as intuitive as the problem domain which we saw. Client orders is a function which takes a client order sheet which models the flexible format of the client and it generates a list of order. Order is one of our domain entities. So this gives us a list of domain artifacts, a domain entity. Then we have the execute. Execute function which takes a market which denotes the market where the trade will be executed, where the order will be executed, the account order and it generates a list of executions. And then the allocate which allocates those executions to specific customer accounts and generates a list of trades. So note that each of these terminologies come from the domain directly. This is what we call domain driven design. It is part of the domain vocabulary and if you show this function prototype to a person who is not a programmer but who understands the domain, he will be able to correlate what exactly is going on. This is some constraining of types. As I was telling that we can have some business logic or domain behavior encoded as part of the type system. When we have an execution, the execute method, execution occurs on the broker account. So I can constrain the type of the account to be of type broker account in the execute function. So what this does is the compiler does the checking that nothing except a broker account can be passed on to execute. And the second advantage which we get is that we don't have to write any tests which verifies that the account passed to the execute function is a broker account. So this is one of the sussing ways of encoding business logic or domain logic as part of type constraints. Similarly, the next function allocate, allocation is done on client accounts, trading accounts, trading account of the client. Similarly, we can encode this logic here as part of the types also. So going back to our simplified model, what we have done till now is we haven't defined any of the types. We have just taken some types out of thin air using domain vocabulary. We just know that in order to allocate, you need a list of accounts, you need an execution and it will generate a list of trades. But I have no idea what an account is or what an execution is. So I have taken some types out of thin air. We haven't yet written a single line of implementation and the type names which we have used, types and the function names which we have used come directly from the domain vocabulary. So we have the types which are the domain entities, functions operating on types which are the domain behaviors and some of the laws or business rules which we will see later how to encode. Already we have encoded some laws through type constraints but we will see how to enforce the other laws which we cannot verify through the type system. And in totality we call this the algebra of our API because these three functions when joined together will give me a trade generation function. We haven't yet seen how to join these types together or join these functions together. Let's put it within a module. So we have a module which generates trade that's modeled by the function trade generation but we haven't yet seen at the implementation of this function. We have only seen the declaration of the functions or the algebra of the functions which we will use to define the enhanced domain behavior of trade generation. This is in essence what I call the algebraic design. The algebra is the binding contract of the API. We haven't yet spoken a bit about the implementation of the algebra. We are still lying, we are still in the land of the algebra only, the interface only. In fact, if we have an algebra we can have multiple implementations for this. For example, for various types of markets the implementations may vary. So that I call the interpreter of the algebra. So one algebra can have multiple interpreters and one of the core principles of functional programming is to decouple the algebra from the interpreter so that we can evolve both of them independently. Now let's try to do some algebra on these functions which we defined. This is the original function list which we defined. We make some algebraic manipulations and now we have slightly changed function prototypes. We have removed some of the currying and this is the signature, this is the algebra on which we will do further enhancements. If you look at the simplistic definition of function composition, functions compose only when types align. Here you see the first function returns a list of order but the second function takes an order as an input. It doesn't take the list of order, it takes an order as an input. These are some of the pattern. Similarly for the second one we have the list of executions and executions. So what we need to do is we need to change these functions together. Our ultimate intention is to change these functions together so that together they can generate a trade for me. So somehow we need to align those types so that I can apply function composition on them and ultimately design the entire function. Now this pattern, remember this pattern, I will, the three functions are a generalized version of or specialized version of this general problem. It's a function f which takes a to list b, then g takes b to list c and h takes c to list d. A problem of composition with effects. It's not simple composition. We need to compose these functions together in presence of the effects. List is an effect, effectful data type. What is the effect? The effect of aggregation. Similarly option. Option is an effectful data type which gives you the effect of optionality. Now in computer science we often see that some problems are solved more easily if we generalize them. So instead of solving the problem of composition with effects using list, why don't we try to solve it using a generalized version of the effect of list which is a monad? So our functions generalize to this thing. If we pass for m as a monad, we have a function f which takes an a and gives me an m of b. A function g which takes b and gives me an m of c. Similarly h takes c and gives me an m of d. Now it so happens that every functional programming library contains an aggregation algebra called clisly. Clisly is an abstraction for the computation a to m b. And in clisly we have we can define a combinator and then it's named and then usually which takes one more computation b to m c and returns you an a to m c. Exactly the composition that we are looking for. Instead of writing ourselves we see that this is already a part of a verified algebra which comes as part of functional programming libraries. So we can use this combinator and then on a computation a to m b and b to m c and we compose them together and get a to m c. We call this effectful function composition and note that and then we have a for and then we have a constraint that m has to be a monad and that's that also exactly fits our requirements because we are trying to compose lists the effect of lists which is a monad. So in that case we need to change the algebra of our function a bit. So in the case of what we did earlier we will model it in terms of the algebra of clisly. It's basically the same thing as earlier we have just introduced the algebra of clisly. Client order sheet to list of order this is now changed to a clisly abstraction. And now we can just follow the types. And our domain algebra is now composed with the categorical algebra of a clisly arrow. We have imported the algebra of clisly arrow incorporated it as part of our domain algebra. And what it gives us is it gives us an easier implementation of the semantics of our domain algebraically. Note we are trying to compose these three functions we don't have any of the implementations. We don't have any of the implementations of these three functions and yet we are trying to compose these together to form a larger behavior. And this is what we get you just since we align the types based on the semantics we needed and we got the algebra of clisly for free. We can just use the end then combinator to write these three lines which is the complete model for generating trade out of customer orders via some intermediate processing and execution. And despite the fact that we didn't have any of the function bodies we have the complete function body of this function trade generation this is all you need. And the best part is that since we use the algebra of clisly and we use the monad yes client yeah client order no no client orders is the name of the function the name of the function yeah ok. And the best part is that since we use the algebra of clisly it does the does the entire error handling for me. I don't have to write any specialized error handling to break the chain in case any of the steps fail. All of those are encapsulated as part of the clisly and monad algebra. So client orders and then execute and then allocate this also rolls in very nicely with the domain behavior sequence that the problem domain mandates. So this is one example where the implementation follows the specification the specification we defined earlier as the three steps these three invocations model the specifications to the T and we get the ubiquitous language for free. This is this resonates with the domain vocabulary as I was telling and if you show this example to someone who who doesn't understand programming you will be able to figure out what's going on as far as the business is concerned as from the business point of view. So this is an example of an implementation which is which is algebraic and functional. We just use pure pure functions and we used the compositional power of algebras. Now we are not done yet we have used lots of effect effectful functions they are effectful function composition using clisly but we haven't yet done anything which will allow us to customize the error handling logic. In the earlier example if there was any error if there was any error in any of the steps then the sequence will break automatically that's what we want but we would also like to report some errors to the user as to what exactly happened. So our algebra still doesn't allow customizable handling of errors that may occur within our domain behaviors. So we need more algebra and more types because our first attempt will be to encode any sort of effect using the type system if we can if we can't then we will resort to other tactics note in in these functions we were returning list of order list is the return type constructor. What happens in case the operation fails we will implement error handling as yet another effect which we can stack on to the existing existing effects. So what this gives us is it it doesn't have side effect it's pure and functional it blends very nicely with our explicit algebra that we published and it's stackable with the existing effects. So we stack list with some other effect called M this is the strategy that we will going to follow we will see that M can be a monad M has to be a monad and how many of you are familiar with transformers monad transformers. Just a brief a brief introduction when we have these kinds of effectful types if we don't use monad transformers then we have to test for comprehension in order to get to the desired type here it's string or option a it's a disjunction with the value being an option. So if we do a monadic comprehension on this first we will the first step will take us take us inside the disjunction and the second for comprehension will take us to the option. So ultimately we can use C here at this level of indirection. So you can imagine the imagine the plight if it were much more complicated then you would have a list of nested for comprehension. We solve this once again by using monad transformers which which collapses the monads you give and gives you back a single monad. I am not going into the details of this example but here option T is a monad transformer which actually fuses the two monads and gives you a single one. So that you can now get to see using a single for comprehension and the essence of this entire exercise is we get a richer algebra. So we use a list transformer we use a list transformer what we what we ideally want to get out of here is that we want to get a list of order in case the function goes ok or otherwise we want to get an error that is what list transformer will give us. So earlier where we had the list we now enrich list enrich that argument with the algebra of a monad transformer and we change it to something we call valid which indicates if the return type is a valid artifact or not and what is valid? Valid is the fusion of the two monads. So what we have here is we have we have kept the kept the signature of our function minimally impacted by this change. We have added the capability of customizable error handling without any significant change in the method signature or as we can see later in the implementation. It just enriches the algebra of the return type and the algebra will encode the logic for handling the error. So you have a small change in algebra the list is changed to valid now which is basically a list transformer. But it is a huge step for our domain model because our domain model can now handle exceptional conditions can now handle errors and report it properly to the user. So earlier it was like this without the error handling part and with the error handling part it is just the encoding of the list T. You just wrap it within a list transformer and you get the desired effect of handling errors. So within as part of our domain model we used some of these we did not use future till now of course but we used some of the some of these algebra of types to encode our domain model and the beauty of this is that these algebras compose composition. You can stack one on top of the other to get the desired effect and by doing this you are also encoding some part of business logic or domain behavior as part of the stack. So the algebra is compositional it offers a suite of functional combinators you can define functional combinators of your own or you can reuse the ones which you inherit from the algebras which you reuse. Handles edge cases so that your domain logic remains clean. Those combinators which you get from monad or clisly those handle the edge cases. So your code your application code remains clean. Your application code doesn't contain the litterings of error handling code and implicitly encodes quite a bit of domain rules. So this is the algebra. We have the functions. We have the types. We have the composed domain behavior. Now I was talking about some of the business rules or domain rules which we need to honor and some of those which we cannot verify as part of cannot encode as part of the type system. For this we can have property based testing where we define algebraic properties for our domain model for the business logic and we use property based testing libraries like quick check or in Scala we have Scala check. We can use these kinds of libraries to define some of the business rules. These are some of the laws of the business which I defined. And if you run through all of the run through those libraries they will report errors. They will generate data based on distributions and will report errors to you. So domain rules as algebraic properties it's part of the abstraction equally important as the actual abstraction because they help you verify the laws of your abstractions laws of your domain and they are verifiable as properties. A simple example from our domain property based testing you can define generators for all actually will generate data for you and you can it's actually powerful very powerful. And if you are more interested in this topic I have written a book which came out very recently functional and reactive domain modeling. It discusses algebraic and functional domain modeling as well as how to make your domain models reactive using the book is the book is written using mostly Scala and Acca. So and you will find lots of similar examples in the book. That's all I have. Any questions? Clarify a bit I didn't get the question. Multiple domains means overloading function overloading. The argument types are different you mean? Yeah you write separate functions for that. If they are semantically different then you can write separate functions or you can use function overloading also which I don't like much but and talking about modeling related functions or related functions on a single object there are actually some of the advanced patterns like type classes which you can use in order to model a group of related functions. Yes actually the book by Eric Evans it's one of the classics. It's one of the classics of domain driven design to understand the subject. And the book is written entirely in the code examples are in Java and uses object oriented techniques. What I have done is I have been thinking about this for quite some time now that how to model domain driven design in terms of functional programming and exactly not everything is pure in the real world. The two main techniques that I used to circumvent this is one of them is free monads. With free monads I define the data type, I define the algebraic data type and then define the interpreter and the other one is plain monads, monad transformers. But once you hide them as part of your library you can always expose some good APIs. Modeling UI. Yeah but if you can define an algebra for it then it should not be a problem. In UI there are maybe some specific nuances. I'm not a UI expert or I haven't designed much of the UIs but I think there are some very cool libraries in pure script which uses functional programming for designing UIs and Brian is not here. Brian is giving a workshop on pure script developing user interfaces using pure script I think tomorrow or day after. So that's worth checking out. But the most important thing is to define the algebra. If you can define the algebra in that case you should be able to model it as part of your implementation. I'm not sure I get your question because function, you can encode the logic as part of the body of your function. If a function returns something you can always encode it as part of the logic. If you can encode it as part of the type, if you model the function as a parametric one or polymorphic one then you have a type as a parameter. Then you have types as parameters to the functions. So that if you can always constraint, you can define constraint genericity of the types, you can resort to parametricity and things like that to define the constraints at the type level. If you don't want to do that or if your logic is such that it cannot be constrained as part of the types then you can always constrain it as part of the logic of the function. If you have the logic of the function clear then why it should be difficult to model? I think we can take it offline. Any more question? Yeah, actually it depends because Eric Evans book discusses the fundamental concepts of domain-driven design. The basic terminologies like bounded context and the repositories originated from his text. His book is a classic which gives you the basics, which gives you a basic understanding of domain-driven design. After that you can read any of the books. So your book about functional domain modeling, so is it only applicable to Scala or we can use other languages like Haskell, for example, if it's using a lot of bounded types, bounded polymorphism instead of type classes then maybe it will be difficult to understand. I just want to know. Yeah, the concepts which I present in the book are applicable for any functional programming language as long as it's statically typed. So Scala and Haskell are good examples. The examples which I give are based on Scala but you can very well translate it to Haskell. It can be done quite easily but the constraint is that it has to be a statically typed language because most of these things which I do are based on type polymorphism and type constraints and parametricity, so these make more, possibly these make more sense in a statically typed language. Subtyping, no, no, no. Almost, yes. Actually, since it's based on Scala, I have subtyping in some of the cases because some of the cases because they are naturally modeled as subtypes, for example, type classes, for type algebraic data types, they are naturally modeled as subtypes. Still we have better encoding which we hope to get. Okay, thank you.