Replies: 6 comments 1 reply
-
Hi @dshunfen , thank you for reaching out! There are people using DF in various contexts: backend, bff, and frontend of different kinds so I feel like adding more examples to that folder as well. |
Beta Was this translation helpful? Give feedback.
-
@gustavoguichard Thanks for this! Would be happy to take a stab at the unit tests. Do you think you could give me an idea on how you would approach it? |
Beta Was this translation helpful? Give feedback.
-
Yeah, I've used it in Remix, Next, Express, and Astro and I've heard about people using it in all of the above + Firebase functions, AWS lambdas, Vue + Nuxt I'll reply later with an example of DF tests. But basically the DFs can be tested almost as pure functions (unless there's something like fetch, DB interactions, and other side effects in it), we mock whichever external interfaces or use a testing DB and we test the happy path with I'm AFK now, will get back to you soon ;) |
Beta Was this translation helpful? Give feedback.
-
@dshunfen I would be careful not to take the DDD / ports and adapters analogy too far. These were inspirational, but this library was not an attempt to implement them "as is". The main idea is to enable a standard representation for business logic ( Now to your points:
I hope I have not created more confusion. I believe @gustavoguichard 's example on testing will shed more light on our style of testing. It does not mean you cannot create your own ;) |
Beta Was this translation helpful? Give feedback.
-
@gustavoguichard @diogob Thank you both for the thoughts. I'm realizing now this really belonged in the I like what I'm hearing, and what you're saying is definitely clarifying rather than confusing. Totally see what you mean and agree with these two points from my perspective:
The last point:
There's two ways I've thought about approaching using DF's (pardon my pseudocode):
Again, thanks for the conversation. Would love to hear your opinions on these two approaches. |
Beta Was this translation helpful? Give feedback.
-
@dshunfen I believe both examples are good in their own style. I gravitate more towards the first one since I rather use DFs all the way down keeping fewer concepts in my head. Regading the adapter swapping, in the example it would not make a lot of sense since there is very little logic in the DFs (the pipe does most of the job). But let's consider an example with some conditional logic: const makeGetSession = mdf(zod.object());
const getSession = makeGetSession(((args, context) => {
return cookie.session.getSession();
})
const authorizeUser = mdf(zod.object(), zod.object())(((args, context) => {
if(!context.admin)
throw new NotAuthorizedError();
return args.org.id;
})
const makeGetUsers = mdf(zod.object({ org: z.object({id: z.number()}) }))
const getUsers = makeGetUsers(((args, context) => {
return prisma.getUsers(org: args.org.id);
})
const listUsers = pipe(getSession, authorizeUser, getUser); Note that I also have extracted the first bit of the DF definition that takes the parsers just to simplify the following example. const getSessionMock = makeGetSession(((args, context) => {
return { org: { id: 1 } };
})
const getUsersMock = makeGetUsers(((args, context) => {
return [];
})
const listUsersWithMocks = pipe(getSessionMock, authorizeUser, getUserMock); Just keep in mind that these are all didactic examples. Beware of extracting functions too early so you won't get a soup of unintelligible DFs. |
Beta Was this translation helpful? Give feedback.
-
I love the idea behind this and the idea here to both maintain typing but separating business logic. And I see it's explicitly pointed out that the project:
It would be great to see some examples of testing the domain logic in the example project.
The way I'm seeing the mapping of this project on to DDD/Clean/Hexagonal principles is that:
loader
andaction
functions act as the abstraction layer for the core domain logic. Meaning, only the business logic using domain entities (hiding implementation-specific details) should exist theredomain-function
type and zod validation are essentially the interface (i.e. port)domain-function
itself is the real infrastructure-specific low-level logic (i.e. adapter)Is the above a correct assessment?
I'd like to understand how to be able to use different "adapters" for the
domain-function
ports.For example, here in your example app:
It would be a big win for me (and would really hit home the intention of this project) to see a unit test added to this example that tests the core business logic in the loader and swaps the "adapter"
domain-function
which currently makes a call to'https://jsonplaceholder.typicode.com'
and instead invokes anotherdomain-function
adapter which is either a mock or pulls the user from a DB/Cache/etc.Beta Was this translation helpful? Give feedback.
All reactions