I like the Partial application approach, I use it in Typescript with a custom DI container which resolves also functions, not just class instances.
/**
* Configures a function for dependency injection, dependency types are automatically inferred based on
* the passed `deps` configuration. Dependency configuration is provided as last argument.
*/exportfunctionconfigure<TDependenciesextendsDependencyDefinitions,TFunctionConstructorextends (dependencies:A.Compute<Dependencies<TDependencies>>)=>TFunction,TFunction>(func:TFunctionConstructor,deps:()=>TDependencies){constinjectedFunc=(funcasany)asConfiguredFunction<TDependencies,TFunctionConstructor,TFunction>injectedFunc.$$inject=depsreturninjectedFunc}
called like so:
constmyFunction=configure(function ({dep1,dep2}){// the types of dep1 and dep2 are inferred.return (input:string)=>...dostuff},()=>({dep1,dep2}),// a function, so that it supports late-binding)
Of course you could store the dependency configuration also in some map, instead of writing onto the function, it works fine like this in Typescript, not sure you could do this in other languages.
as to
though you could also argue that we'd do that at the expense of having the business logic pushed to the outer layers just so we can have a pure functional core
I'm not sure how the list of todos is considered business logic. So retrieving data is imo something we can do in the app layer. Impure effects however, e.g on 3rd party apis, message busses, etc, I would handle with Domain events - do all the business decisions, logic, policy in the domain, put the decisions in an Event and let the event handlers call the relevant infra.
Senior Software Engineer at Noom, formerly Team Lead Engineering at XING. I intend to write about functional programming and occasionally some random engineering topic.
Thanks for sharing! I'm not familiar with the JS/TS world but out of curiosity and ignorance, why not Lodash or Ramda? Don't they support partial function application? What is the purpose of late-binding (assuming the dependencies are immutable references)?
I'm not sure how the list of todos is considered business logic. So retrieving data is imo something we can do in the app layer. Impure effects however, e.g on 3rd party apis, message busses, etc, I would handle with Domain events - do all the business decisions, logic, policy in the domain, put the decisions in an Event and let the event handlers call the relevant infra.
Agreed, that sounds like an approach where the code would be pure. I was referring to the difference between
I'm a fan especially of Rambda (notice bd), I use it a lot and like it. I throw in some Lodash once in a while, when I need some of their helpers for a specific problem.
The problem with the various ways of composition in Typescript is some loss of (generic) type inference. I think Lodash barely tries. Rambda does way better, I would have to look into Ramda to check how they fare. If TS will receive placeholder generic types, this might improve.
Such type inference is very valuable to me, it is one of the things I like the most about Typescript; types are optional - although I use them extensively, and the inference goes a very long way, together with derivative types, to potentially reduce a lot of manual typing (Pick, Omit, Partial, NonNullable, ReturnType, to name few built-in. But one can go extreme; github.com/pirix-gh/ts-toolbelt)
So far i'm using github.com/gcanti/fp-ts (and all it's friends like io-ts etc). But i'm still not sure of the verbose syntax. I can't wait until the pipe operator (|>) in JS/TS lands, in the hopes that will resolve some of the boilerplate and verbosity. But maybe i'm really just ready for Kotlin, F# and friends..
What is the purpose of late-binding (assuming the dependencies are immutable references)
I like to be able to define less abstract functions below my most abstract one (in class world, basically from Public to Private methods). Without late-binding I would have to define those functions above instead.
Also it helps a little bit with some annoying cyclic references between files at times - although those should generally be avoided anyway.
I was referring to the difference between
I agree, but that means I still don't understand the sentence.
I read it as:
"If you do this:
val todos = repository.getUserTodos(userId)
getCompletedTodos(todos, userId)
You essentially push business logic to the outer layers, for the sake of having a functional core."
But I don't see how doing this is moving business logic.
Perhaps i'm misreading ;-)
Senior Software Engineer at Noom, formerly Team Lead Engineering at XING. I intend to write about functional programming and occasionally some random engineering topic.
Follow-up, I think my confusion comes from our different definition of the Domain.
See for example this naive implementation in Typescript, for how I see it: gist.github.com/patroza/8f2d634b23...
Main take aways:
The Interactor is not Domain, but Application, and is allowed to leverage interfaces from Infra.
The return view from the Interactor is complete, including userId. The only job of the Controller (request handler) is to transform HTTP request details into basic data structure for input to the interactor, and to transform the Response from the basic data structure into JSON.
I added a completeTodo mutation, because I think commands are a lot more interesting, because they require business rules/policy to be applied usually - which is where the domain model shines.
where-as queries are often just bolted on top of database/remote apis, just a simple View, often pre-generated in a model convenient for Reading (if you follow CQRS for sure).
Finally, I think that for the Interactor taking the input as parameters and resolving the result by returning it as value, is a shortcut to the Clean Architecture's "Controller" calls Input interface implemented by "Interactor" and "Interactor" calls Output interface implemented by "Presenter", but I found that I hardly need the extra level of complexity it brings if you go literal.
Senior Software Engineer at Noom, formerly Team Lead Engineering at XING. I intend to write about functional programming and occasionally some random engineering topic.
Indeed, we had different definitions of Domain. I was thinking in terms of three layers: Presentation, Domain and Data, where domain includes business rules that are encoded in the use cases or interactors, like depicted here from this post.
If I'm understanding well what you say, your layers are the ones suggested in Clean Architecture by Uncle bob where you have, from inner to outer circles:
Domain models and functions that can transform them
Application layer that decides what domain models and what transformations to use and handle interactions with infra/presentation
Infra/Presentation - this would be where the data comes in or goes out.
Makes a lot of sense too, it reminds me of the "ports and adapters" architecture, where your infra/presentation functions would be the ports and adapters. My understanding of Domain is basically Application + Domain in your case I'd say.
I think we're talking about the same thing. In your code
getCompletedTodos is pure iff getTodos is pure. To make it 100% referentially transparent you'd have to pass the Todos, but then the getTodos logic would be pushed to the infrastructure layer.
Small nit: you could make your domain pure by passing in new Date() instead of instantiating it within complete.
I would say we got as far pure as makes sense. The HTTP Request Handler can't be pure, and the application use-case interactor shouldn't be pure, imo - at least if you like the Interactor to still add meaningful value and sticking to the fact that the Request Handler is just a delivery mechanism detail. However the pure business case, is pure.
I would say that the Interactor is the red parts here, blog.ploeh.dk/2020/03/02/impureim-... while the HTTP request handler is just the mount point for this usecase or workflow.
They do something similar in fsharpforfunandprofit.com/ddd/ which im a huge fan of, I read his book and am intruiged by his railway oriented programming.
Small nit: you could make your domain pure by passing in new Date() instead of instantiating it within complete.
Update:
Regarding the post; fernandocejas.com/2014/09/03/archi...
I find the demo project a little boring due to it only implementing Queries, and the Interactors doing nothing more than redirecting calls to a Repository. At least some mapping of Entities to Views would be interesting, but Commands would be of more interest to me :)
I'm personally also more fan of Database contexts, which give lower level access to the data, instead of the more high level one exact query per method like in Repositories, as often in my experience each method is actually only used once, or maximum twice anyway.
But of course you don't give your entities access to these database contexts, that remains in the Interactor. Anyway, it depends on the project.
Old but gold: lostechies.com/jimmybogard/2015/05...
Basically I see Interactors as either Queries or Commands as per how JimmyBogard described them.
What I like about this pattern also is that you can extend the Mediator pipeline with additional behaviours through decorators like validating requests, performing authentication, etc.
Finally - if you're interested, here are some of my own experimentations with all these patterns, in a Functional Programming style, latest fp-ts version github.com/patroza/fp-app-framework2
It's doing CQRS with separate read and write contexts - file-based json databases - living the Uncle Bob dream ;-), domain events, DI, exploring functional programming and trying to find a balance between FP and OO, e.g FP-OO-FP sandwich, which may or may not lead to a 100% FP implementation ;-) Multi level validation (basic JSON fields in delivery mechanism, and Domain level validation in the Interactors/Domain objects)
It's runnable, and has a documented schema so you can easily discover what to post.
Senior Software Engineer at Noom, formerly Team Lead Engineering at XING. I intend to write about functional programming and occasionally some random engineering topic.
How about the Exception? Is that considered Pure? The alternative would be the use of Either.
I'd say that if the exception is recoverable it's not really an exception but a valid case so it should be modelled as such.
For example, you could have something like
typeTodo=IncompleteTodo|CompletedTodo
and then you get compile-time verification plus no exceptions. I just happen to have written about it very recently (shameless plug :D).
I find the demo project a little boring due to it only implementing Queries, and the Interactors doing nothing more than redirecting calls to a Repository. At least some mapping of Entities to Views would be interesting, but Commands would be of more interest to me :)
Yeah, the example is perhaps a bit too simple, but the repository pattern is useful because it abstracts from the data source that's going to be used. From an interactor's point of view, it only wants to fetch data from a repository, but it doesn't care if this data comes from a disk file, database or Redis. These data sources can even be mixed, you might want to check if you've got something in Redis and if not, go fetch it.
Old but gold: lostechies.com/jimmybogard/2015/05...
Basically I see Interactors as either Queries or Commands as per how JimmyBogard described them.
That's a nice one. If we simplify things to the extreme, you can strip classes and interfaces and have only functions left. We can think of interactors like modules of query/command functions and if these are pure, it should be very easy to compose them with extra functionality such as validation or authentication.
I'd say that if the exception is recoverable it's not really an exception but a valid case so it should be modelled as such.
Fair enough. Will definitely check your post.
but the repository pattern is useful because it abstracts from the data source that's going to be used
I agree, I guess the main difference is just - do you put all functions in a Repository class, or do you have a bunch of separate functions - perhaps living closer to the usecases that they are used in, perhaps even as private functions to the usecase (function or file), i'm leaning more to the latter, as growing a repository class with single use functions seems to me just not that useful. It centralises them, but as they're often single-use, their ideal place seems to be more close to their use.
That's a nice one. If we simplify things to the extreme, you can strip classes and interfaces and have only functions left.
Yep, 100 with you, I prefer doing this with functions. When the language allows, doing this with just functions is awesome.
Except on the pure part; i'm fine with the Interactors depending on impure functions (only known by interface, not implementation), imo that's their main purpose;
receiving input from delivery mechanism - calling impure, pure, impure - producing output for the delivery mechanism.
Of course Jimmy has a word on that too ;-) lostechies.com/jimmybogard/2012/10...
(it stands at the basis for the Query/Command handlers, which is an evolution of this)
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
I like the Partial application approach, I use it in Typescript with a custom DI container which resolves also functions, not just class instances.
called like so:
Of course you could store the dependency configuration also in some map, instead of writing onto the function, it works fine like this in Typescript, not sure you could do this in other languages.
as to
I'm not sure how the list of todos is considered business logic. So retrieving data is imo something we can do in the app layer. Impure effects however, e.g on 3rd party apis, message busses, etc, I would handle with Domain events - do all the business decisions, logic, policy in the domain, put the decisions in an Event and let the event handlers call the relevant infra.
Thanks for sharing! I'm not familiar with the JS/TS world but out of curiosity and ignorance, why not Lodash or Ramda? Don't they support partial function application? What is the purpose of late-binding (assuming the dependencies are immutable references)?
Agreed, that sounds like an approach where the code would be pure. I was referring to the difference between
vs
In the first version,
getCompletedTodos
is referentially transparent only ifrepository::getUserTodos
is too, which can't be guaranteed.Thanks for the response!
I'm a fan especially of Rambda (notice
bd
), I use it a lot and like it. I throw in some Lodash once in a while, when I need some of their helpers for a specific problem.The problem with the various ways of composition in Typescript is some loss of (generic) type inference. I think Lodash barely tries. Rambda does way better, I would have to look into Ramda to check how they fare. If TS will receive placeholder generic types, this might improve.
Such type inference is very valuable to me, it is one of the things I like the most about Typescript; types are optional - although I use them extensively, and the inference goes a very long way, together with derivative types, to potentially reduce a lot of manual typing (Pick, Omit, Partial, NonNullable, ReturnType, to name few built-in. But one can go extreme; github.com/pirix-gh/ts-toolbelt)
So far i'm using github.com/gcanti/fp-ts (and all it's friends like io-ts etc). But i'm still not sure of the verbose syntax. I can't wait until the pipe operator (|>) in JS/TS lands, in the hopes that will resolve some of the boilerplate and verbosity. But maybe i'm really just ready for Kotlin, F# and friends..
I like to be able to define less abstract functions below my most abstract one (in class world, basically from Public to Private methods). Without late-binding I would have to define those functions above instead.
Also it helps a little bit with some annoying cyclic references between files at times - although those should generally be avoided anyway.
I agree, but that means I still don't understand the sentence.
I read it as:
"If you do this:
You essentially push business logic to the outer layers, for the sake of having a functional core."
But I don't see how doing this is moving business logic.
Perhaps i'm misreading ;-)
Thanks a lot for this very high quality response, it all makes sense. I'm very intrigued by TypeScript right now to be honest, will give it a try :)
Follow-up, I think my confusion comes from our different definition of the Domain.
See for example this naive implementation in Typescript, for how I see it:
gist.github.com/patroza/8f2d634b23...
Main take aways:
Finally, I think that for the Interactor taking the input as parameters and resolving the result by returning it as value, is a shortcut to the Clean Architecture's "Controller" calls Input interface implemented by "Interactor" and "Interactor" calls Output interface implemented by "Presenter", but I found that I hardly need the extra level of complexity it brings if you go literal.
Indeed, we had different definitions of Domain. I was thinking in terms of three layers: Presentation, Domain and Data, where domain includes business rules that are encoded in the use cases or interactors, like depicted here from this post.
If I'm understanding well what you say, your layers are the ones suggested in Clean Architecture by Uncle bob where you have, from inner to outer circles:
Makes a lot of sense too, it reminds me of the "ports and adapters" architecture, where your infra/presentation functions would be the ports and adapters. My understanding of Domain is basically Application + Domain in your case I'd say.
I think we're talking about the same thing. In your code
getCompletedTodos
is pure iffgetTodos
is pure. To make it 100% referentially transparent you'd have to pass the Todos, but then thegetTodos
logic would be pushed to the infrastructure layer.Small nit: you could make your domain pure by passing in
new Date()
instead of instantiating it withincomplete
.Thanks!
I would say we got as far pure as makes sense. The HTTP Request Handler can't be pure, and the application use-case interactor shouldn't be pure, imo - at least if you like the Interactor to still add meaningful value and sticking to the fact that the Request Handler is just a delivery mechanism detail. However the pure business case, is pure.
I would say that the Interactor is the red parts here, blog.ploeh.dk/2020/03/02/impureim-... while the HTTP request handler is just the mount point for this usecase or workflow.
They do something similar in fsharpforfunandprofit.com/ddd/ which im a huge fan of, I read his book and am intruiged by his railway oriented programming.
Very good point! I'm still too stuck in non FP languages, that I don't realise these subtle cheats :)
gist.github.com/patroza/8f2d634b23...
How about the Exception? Is that considered Pure? The alternative would be the use of Either.
Update:
Regarding the post; fernandocejas.com/2014/09/03/archi...
I find the demo project a little boring due to it only implementing Queries, and the Interactors doing nothing more than redirecting calls to a Repository. At least some mapping of Entities to Views would be interesting, but Commands would be of more interest to me :)
I'm personally also more fan of Database contexts, which give lower level access to the data, instead of the more high level one exact query per method like in Repositories, as often in my experience each method is actually only used once, or maximum twice anyway.
But of course you don't give your entities access to these database contexts, that remains in the Interactor. Anyway, it depends on the project.
Old but gold: lostechies.com/jimmybogard/2015/05...
Basically I see Interactors as either Queries or Commands as per how JimmyBogard described them.
What I like about this pattern also is that you can extend the Mediator pipeline with additional behaviours through decorators like validating requests, performing authentication, etc.
Finally - if you're interested, here are some of my own experimentations with all these patterns, in a Functional Programming style, latest fp-ts version github.com/patroza/fp-app-framework2
It's doing CQRS with separate read and write contexts - file-based json databases - living the Uncle Bob dream ;-), domain events, DI, exploring functional programming and trying to find a balance between FP and OO, e.g FP-OO-FP sandwich, which may or may not lead to a 100% FP implementation ;-) Multi level validation (basic JSON fields in delivery mechanism, and Domain level validation in the Interactors/Domain objects)
It's runnable, and has a documented schema so you can easily discover what to post.
I'd say that if the exception is recoverable it's not really an exception but a valid case so it should be modelled as such.
For example, you could have something like
and then you get compile-time verification plus no exceptions. I just happen to have written about it very recently (shameless plug :D).
Yeah, the example is perhaps a bit too simple, but the repository pattern is useful because it abstracts from the data source that's going to be used. From an interactor's point of view, it only wants to fetch data from a repository, but it doesn't care if this data comes from a disk file, database or Redis. These data sources can even be mixed, you might want to check if you've got something in Redis and if not, go fetch it.
That's a nice one. If we simplify things to the extreme, you can strip classes and interfaces and have only functions left. We can think of interactors like modules of query/command functions and if these are pure, it should be very easy to compose them with extra functionality such as validation or authentication.
I'll check your repo, thanks :)
Fair enough. Will definitely check your post.
I agree, I guess the main difference is just - do you put all functions in a Repository class, or do you have a bunch of separate functions - perhaps living closer to the usecases that they are used in, perhaps even as private functions to the usecase (function or file), i'm leaning more to the latter, as growing a repository class with single use functions seems to me just not that useful. It centralises them, but as they're often single-use, their ideal place seems to be more close to their use.
Yep, 100 with you, I prefer doing this with functions. When the language allows, doing this with just functions is awesome.
Except on the pure part; i'm fine with the Interactors depending on impure functions (only known by interface, not implementation), imo that's their main purpose;
receiving input from delivery mechanism - calling impure, pure, impure - producing output for the delivery mechanism.
Small follow-up on Repository, so i'm kind of more in the boat of:
and then using these functions in the interactor, instead of encapsulating specific queries in single use methods in the Repository.
Of course Jimmy has a word on that too ;-)
lostechies.com/jimmybogard/2012/10...
(it stands at the basis for the Query/Command handlers, which is an evolution of this)