I feel like you could describe the abstractions you built in more detail. When I read the explanation for what the 'UseCase', 'App', 'Product' and 'Target' were, it wasn't clear how each of those translates to TypeScript. My guess is that 'UseCase' and 'App' would be like Classes, if you're modeling your program in an OOP way? The 'Product' seems like it would be the TypeScript project itself, with the package.json, source code and all of that.
I would rethink how you named the 'App' layer. The examples given ('auth', 'accounting', etc.) are not necessarily what I would call an 'app'.
As you introduce names and concepts for things in your library, I recommend trying to keep the cognitive load as low as possible. It seems like there are a very high amount of high-level concepts and implementation details like types, functions, etc. that 1. are specific/unique to libmodulor and 2. you need to learn before you can start actually building your application, from looking at the examples. The barrier to give it a try in a side project seems really high.
Building things is cool regardless :) I'm happy that you built something it's useful to you and that you got to share here.
> it wasn't clear how each of those translates to TypeScript
That's a fair point. I will add more details on how each of these notions translates to TypeScript. Quickly :
- UseCase : a file containing the use case definition
- App : a directory with a use cases folders and metadata (i18n, metadata)
- Product : a directory with a apps folders and metadata (i18n, metadata)
- Target : depends on it by for a GUI it's the screens where use cases are injected
> I would rethink how you named the 'App' layer
I'm not a huge fan of this name either, but couldn't come up with something better at this time. `Module` seemed to broad to me. Although the notion is not totally clear to you, do you have any ideas in mind ?
I agree that it's not as straightforward as other solutions at this moment. I'll keep working and improving this to reduce the time needed to get started.
But I’m still a bit confused on what the project actually “is”. I see you have an architecture and I’m using ts to define the interface between those 4 types of components. But let’s say I have a react-native target: what am I expressing in that interface? A cli which can build/deploy that interface? Each ui screen in that rn app (rn login, rn add contact)? Or all of the api endpoints in the web target which gets called by the rn target?
In the readme, I would focus a bit less on the UML part, and a bit more on the “if I have a webapp and a mobile app, with auth and crud for contacts, here’s what you’d need”
Let's say you want to create a product with auth and crud for contacts. You'll have a SignInUCD, a CreateContactUCD, a AddPhoneNumberToContactUCD, etc.
Since react-native expects `<View>`, `<Text>` and not `<div>`, etc. you'll also need to define your "design system", like it's been done here for example : https://github.com/c100k/libmodulor/tree/master/dist/esm/tar.... Basically, you need to define how you want a use case form to be displayed, etc. When in web we rely on `<input>`, in react-native we'll rely on `<TextInput>`. And of course, according to the data type, you can display a specific form control.
I realize it's super hard to explain and I'm not clear enough but hopefully I'll find the best way to express it.
Let's say I'm using shadcn's Dialog [1] on my web target, which has many subcomponents (Dialog, DialogTrigger, DialogHeader, etc). How many of those am i representing with a 1-to-1 `UC`? Is it just the parts that are on the IO seam, like a UC for opening the dialog, UC for closing a dialog, and UC for submitting a dialog? Or is it also for things the user sees like UC for header, UC for content, UC for buttons panel?
There is obviously some cost to expressing the interface between the product/target/usecase. What exact benefit is that cost getting me? do i know that if i expose a certain use case in one target then i have to explicitly decide if i'm going to expose (or not expose) it in a different target, which helps me get consistency/governance between my app as it grows? does it help me "integration test" by application in isolation, in a "similar" way that pact [2] helps with integration testing microservices? (ex: the mobile app relies on X input, but from the ts interfaces, the tool can detect that the web-api is no longer defining an output for that api. if so, is this on the /api/v1/resource level? the openapi schema for a json body response level?). do i get a mono-build-system, where everything flows together and i just say "libmodulor build" and "libmodulor deploy" and I'm good to go?
said in another way: many of the people on HN have a backend api, a react SPA, and a mobile app. what types of problems do i have now which libmodulor solves?
Let's take the first example here : https://ui.shadcn.com/docs/components/dialog. In this case, you have only one UC named EditProfileUCD, with the following input => name: PersonFullname and username: Username. All the things related to "UI" are not use cases since they are specific to a GUI target. A good tip to see if something is a UC or not : it should be available on all platforms. Opening a dialog in a Terminal is not for instance.
To continue with this example, you would add a <UCEntrypoint uc={uc} /> in your webpage, referencing EditProfileUCD. According to the client policy defined in the UCD and the UC auth, the button "Edit Profile" will show up or not. You can also simply disable it.
And your Dialog would render a <UCPanel uc={uc} /> that will display the form based on the UC input. Check out the contract of UCPanel (https://github.com/c100k/libmodulor/tree/master/dist/esm/tar...) to see how you can design the form and the form fields. Ideally, you would design these only once, and use <UCPanel uc={uc} /> across your whole codebase.
> said in another way: many of the people on HN have a backend api, a react SPA, and a mobile app. what types of problems do i have now which libmodulor solves?
In this typical architecture, you would benefit a lot from libmodulor. All your business functionality would be expressed as individual use cases, organized in apps corresponding to your business domain. You would have a server target (backend api), a react-web target (react SPA), a react-native target (mobile app). Each of them will bind the appropriate things in their container. The API endpoints will be automatically mounted in your backend API. They correspond to UCDs having a server lifecycle. Adding a <UCPanel uc={uc} /> in react web or react-native will render the same UC for each platform and submit it automatically to the server, without you having to do any plumging whatsoever. You are totally free to expose a UC in web but not in react-native.
> do i get a mono-build-system, where everything flows together and i just say "libmodulor build" and "libmodulor deploy" and I'm good to go?
This is clearly an important part that is non-existent at this time. For my own products for instance, I deploy each based on the target used (push on a PaaS for a server target, webpack/vite for a web target, fastlane for a react-native target, etc.)
If you have some time, I highly recommend to follow the "Getting Started", showing you how you can multiply the targets, re-using the apps as is.
Thanks a lot for your questions, they help me a lot to see where I fail to explain and how I can simplify things.
interesting, when you say websocket support on aws, does this mean ws using lambda? and ws on nextjs (would be a game changer if someone made this happen)
If deploying off of vercel is acceptable, it can be done pretty nicely via serverless-nextjs or nextjs docker in one server. But from what I understand vercel internally does quite a bit of code analysis to split things and I don't really want to get too deep into the weeds in that direction
Also curious how you would want Websocket servers to talk to each other (to broadcast messages). Would you be okay having a pub sub layer like redis that nestjs servers run on?
I find most often people who are opinionated have very little knowledge on the subject. They are opinionated in an effort to try to keep discussions in a realm they feel they have some sort of expertise, but by definition their limited view makes them look silly to those with deeper understanding.
I apologise for being off topic, but I really want “an opinionated X” to stop having some kind of positive connotation to junior devs.
I'm not sure there is a relation between a program/library to be "opinionated" vs the skillset of the person who created it.
In my case, I'm using the word because the library defines a set of rules and conventions to follow. They are indeed based on my experience.
Are they perfect ? Probably not. And I'm totally open to review them if I missed things. That's how we all learn. Like any model (in a mathematical way), it is an approximation of the actual problem.
Limited is not intrinsically bad. Even if someone makes questionable decisions, the act of limiting the scope by defining specific interfaces/patterns has value in and of itself.
I agree, but limited isn’t the same as opinionated. In these types of usage, people seem to think they are opinionated because they are right.
I think it’s misunderstanding the angst of knowledgeable people’s frustration with the world, by trying to emulate the frustration without having the actual knowledge or experience.
I'm a big fan of opinionated software. This world is full of software that tries to do everything. A lot of the times I just want it to do the one thing really well.
I always read "opinionated program" as "I'm immature, don't understand my own opinions, and would rather force my opinions on you than examine my beliefs in any capacity"
Extremely immature and "I'm an asshole and I'm making it your problem" behavior
Congrats on your project.
I feel like you could describe the abstractions you built in more detail. When I read the explanation for what the 'UseCase', 'App', 'Product' and 'Target' were, it wasn't clear how each of those translates to TypeScript. My guess is that 'UseCase' and 'App' would be like Classes, if you're modeling your program in an OOP way? The 'Product' seems like it would be the TypeScript project itself, with the package.json, source code and all of that.
I would rethink how you named the 'App' layer. The examples given ('auth', 'accounting', etc.) are not necessarily what I would call an 'app'.
As you introduce names and concepts for things in your library, I recommend trying to keep the cognitive load as low as possible. It seems like there are a very high amount of high-level concepts and implementation details like types, functions, etc. that 1. are specific/unique to libmodulor and 2. you need to learn before you can start actually building your application, from looking at the examples. The barrier to give it a try in a side project seems really high.
Building things is cool regardless :) I'm happy that you built something it's useful to you and that you got to share here.
> it wasn't clear how each of those translates to TypeScript
That's a fair point. I will add more details on how each of these notions translates to TypeScript. Quickly :
> I would rethink how you named the 'App' layerI'm not a huge fan of this name either, but couldn't come up with something better at this time. `Module` seemed to broad to me. Although the notion is not totally clear to you, do you have any ideas in mind ?
I agree that it's not as straightforward as other solutions at this moment. I'll keep working and improving this to reduce the time needed to get started.
I enjoy your 4 types on the architecture.
But I’m still a bit confused on what the project actually “is”. I see you have an architecture and I’m using ts to define the interface between those 4 types of components. But let’s say I have a react-native target: what am I expressing in that interface? A cli which can build/deploy that interface? Each ui screen in that rn app (rn login, rn add contact)? Or all of the api endpoints in the web target which gets called by the rn target?
In the readme, I would focus a bit less on the UML part, and a bit more on the “if I have a webapp and a mobile app, with auth and crud for contacts, here’s what you’d need”
Thank you for your feedback, I really appreciate.
Let's say you want to create a product with auth and crud for contacts. You'll have a SignInUCD, a CreateContactUCD, a AddPhoneNumberToContactUCD, etc.
As you said, your react-native target will define the UI screens. You are free to design them the way you want as the library does not make any assumptions about the UI/UX. In every screen where you want to "inject" a use case, you'll use the `useUC` hook and `<UCPanel uc={uc} />` (see https://github.com/c100k/libmodulor/tree/master/dist/esm/tar...). See also https://github.com/c100k/libmodulor/blob/master/docs/getting.... It explains for web, but the mechanics are the same.
Since react-native expects `<View>`, `<Text>` and not `<div>`, etc. you'll also need to define your "design system", like it's been done here for example : https://github.com/c100k/libmodulor/tree/master/dist/esm/tar.... Basically, you need to define how you want a use case form to be displayed, etc. When in web we rely on `<input>`, in react-native we'll rely on `<TextInput>`. And of course, according to the data type, you can display a specific form control.
I realize it's super hard to explain and I'm not clear enough but hopefully I'll find the best way to express it.
Let's say I'm using shadcn's Dialog [1] on my web target, which has many subcomponents (Dialog, DialogTrigger, DialogHeader, etc). How many of those am i representing with a 1-to-1 `UC`? Is it just the parts that are on the IO seam, like a UC for opening the dialog, UC for closing a dialog, and UC for submitting a dialog? Or is it also for things the user sees like UC for header, UC for content, UC for buttons panel?
There is obviously some cost to expressing the interface between the product/target/usecase. What exact benefit is that cost getting me? do i know that if i expose a certain use case in one target then i have to explicitly decide if i'm going to expose (or not expose) it in a different target, which helps me get consistency/governance between my app as it grows? does it help me "integration test" by application in isolation, in a "similar" way that pact [2] helps with integration testing microservices? (ex: the mobile app relies on X input, but from the ts interfaces, the tool can detect that the web-api is no longer defining an output for that api. if so, is this on the /api/v1/resource level? the openapi schema for a json body response level?). do i get a mono-build-system, where everything flows together and i just say "libmodulor build" and "libmodulor deploy" and I'm good to go?
said in another way: many of the people on HN have a backend api, a react SPA, and a mobile app. what types of problems do i have now which libmodulor solves?
[1] https://ui.shadcn.com/docs/components/dialog [2] https://pact.io/
Let's take the first example here : https://ui.shadcn.com/docs/components/dialog. In this case, you have only one UC named EditProfileUCD, with the following input => name: PersonFullname and username: Username. All the things related to "UI" are not use cases since they are specific to a GUI target. A good tip to see if something is a UC or not : it should be available on all platforms. Opening a dialog in a Terminal is not for instance.
To continue with this example, you would add a <UCEntrypoint uc={uc} /> in your webpage, referencing EditProfileUCD. According to the client policy defined in the UCD and the UC auth, the button "Edit Profile" will show up or not. You can also simply disable it.
And your Dialog would render a <UCPanel uc={uc} /> that will display the form based on the UC input. Check out the contract of UCPanel (https://github.com/c100k/libmodulor/tree/master/dist/esm/tar...) to see how you can design the form and the form fields. Ideally, you would design these only once, and use <UCPanel uc={uc} /> across your whole codebase.
> said in another way: many of the people on HN have a backend api, a react SPA, and a mobile app. what types of problems do i have now which libmodulor solves?
In this typical architecture, you would benefit a lot from libmodulor. All your business functionality would be expressed as individual use cases, organized in apps corresponding to your business domain. You would have a server target (backend api), a react-web target (react SPA), a react-native target (mobile app). Each of them will bind the appropriate things in their container. The API endpoints will be automatically mounted in your backend API. They correspond to UCDs having a server lifecycle. Adding a <UCPanel uc={uc} /> in react web or react-native will render the same UC for each platform and submit it automatically to the server, without you having to do any plumging whatsoever. You are totally free to expose a UC in web but not in react-native.
> do i get a mono-build-system, where everything flows together and i just say "libmodulor build" and "libmodulor deploy" and I'm good to go?
This is clearly an important part that is non-existent at this time. For my own products for instance, I deploy each based on the target used (push on a PaaS for a server target, webpack/vite for a web target, fastlane for a react-native target, etc.)
If you have some time, I highly recommend to follow the "Getting Started", showing you how you can multiply the targets, re-using the apps as is.
Thanks a lot for your questions, they help me a lot to see where I fail to explain and how I can simplify things.
Ah. Thank you. Having examples up front really helps me understand it better.
You should check out https://effect.website/
It might help you implement some of these ideas
Looks great!
I build something similar (vramework.dev), actually on my way now to give a talk on it
Got a presentation for it at presentation.vramework.dev if anyone is interested
interesting, when you say websocket support on aws, does this mean ws using lambda? and ws on nextjs (would be a game changer if someone made this happen)
Yes it’s ws using lambda, the worker-starter example shows how it works
Also abstracts away the idea of an eventbus which is pretty critical in any Websocket deployment.
It doesn’t use Websocket directly via Vercel, but would work if you use nextjs by providing it a http server and also providing that server to ws
Can get this to work, but I’m pretty curious why you think this is a game changer? Thanks!
Nice. I’m going to look into this more. We currently run a dedicated server next to our vercel apps just for ws support. Adds considerable overhead.
Maybe game changer is an exaggeration but In the vercel community, ws has been a top requested feature for years. See comments on https://x.com/rauchg/status/1872729115595587627
I raised an issue here https://github.com/vramework/vramework/issues/119, feel free to add any info that can help.
Note to self: need to signup to X!
If deploying off of vercel is acceptable, it can be done pretty nicely via serverless-nextjs or nextjs docker in one server. But from what I understand vercel internally does quite a bit of code analysis to split things and I don't really want to get too deep into the weeds in that direction
Thank you for raising!
Also curious how you would want Websocket servers to talk to each other (to broadcast messages). Would you be okay having a pub sub layer like redis that nestjs servers run on?
Also is running on vercel a requirement?
Looks great, will have a look at it.
Thank you!
vramework looks really well thought out. Is it in use by anyone yet?
Heya!
It’s used in three companies so far, but the new productised (via the cli) version is still in development / qa stages
There is one company that has been using it for over four years tho! Just checked in and seems to be working solid
The difference between the two versions is that we now have a cli, whereas before you needed to call scripts to do the same things
I find most often people who are opinionated have very little knowledge on the subject. They are opinionated in an effort to try to keep discussions in a realm they feel they have some sort of expertise, but by definition their limited view makes them look silly to those with deeper understanding.
I apologise for being off topic, but I really want “an opinionated X” to stop having some kind of positive connotation to junior devs.
I'm not sure there is a relation between a program/library to be "opinionated" vs the skillset of the person who created it.
In my case, I'm using the word because the library defines a set of rules and conventions to follow. They are indeed based on my experience.
Are they perfect ? Probably not. And I'm totally open to review them if I missed things. That's how we all learn. Like any model (in a mathematical way), it is an approximation of the actual problem.
Limited is not intrinsically bad. Even if someone makes questionable decisions, the act of limiting the scope by defining specific interfaces/patterns has value in and of itself.
I agree, but limited isn’t the same as opinionated. In these types of usage, people seem to think they are opinionated because they are right.
I think it’s misunderstanding the angst of knowledgeable people’s frustration with the world, by trying to emulate the frustration without having the actual knowledge or experience.
I'm a big fan of opinionated software. This world is full of software that tries to do everything. A lot of the times I just want it to do the one thing really well.
I always read "opinionated program" as "I'm immature, don't understand my own opinions, and would rather force my opinions on you than examine my beliefs in any capacity"
Extremely immature and "I'm an asshole and I'm making it your problem" behavior