feathers icon indicating copy to clipboard operation
feathers copied to clipboard

Component-based architecture

Open issy123 opened this issue 5 years ago • 7 comments

The problem / idea

I am working on front-end a lot and what I find really convenient is that they're component-based structures. This is common in Angular, React and Vue.

E.g. a component 'user' has the following structure

user/
   user.component.html
   user.component.scss
   user.component.test.ts
   user.component.ts
   user.translations.ts

What is so convenient about this? Well If I want to reuse this in another project, i can just move the 'user' component because it has everything it needs inside that folder

How does feathers v4 currently look

Example:

src/
   hooks/
     isAdmin.ts
   models/
     user.model.ts
   services/
      user/
         user.hooks.ts
         user.service.ts
test/
   services/
     user.test.js

My proposed solution

src/
   services/
      user/
         hooks/
            isAdmin.ts
         user.hooks.ts
         user.service.ts
         user.test.ts
         user.model.ts

Why / potential use cases

  • Well if a new developer asks, where do I find x for user? Currently you can answer it depending on what 'x' is, if it's test it's a different place, if it's hooks it's a different place. With the new proposed architecture, it does not matter what 'x' is, you can always point to the user service to find everything regarding the user
  • If a developer checks out your project, and find a really cool service named 'somecoolservice'. With the new proposed architecture you can say, yeah sure go ahead and just copy 'somecoolservice' into your project

Potential downfalls

  • Where would you place a hook that is useful for multiple services ? Do you keep 'isAdmin' in user service and require it from there in other services, or create a shared / lib folder? This can be hard to answer
  • Where would integration tests and tests that not only apply to one service be placed? This can be hard to answer

issy123 avatar Dec 22 '19 21:12 issy123

I think you can create something like this, Currently we have a structure suits per project, https://microsoft.github.io/just/ allows us to create fast generators.

But lets not forget feathers allows us to create backend services. So issues like scaling, more pressing issue I assume. eg. #939

One of the best things feathers provides a utility structure not an app structure allows us to manipulate data easyly. I know it's really far away example but bullma css framework gives you structure, tailwindcss gives you utilities which you can shape UI very easy.

if we move a stucture as component we bind our code to that specific project.

muratbeser avatar Dec 22 '19 22:12 muratbeser

@issy123, what you are proposing is actually my preferred file structure. I proposed this years ago and the main reason that people didn't like it came from the people using ORMs. They really liked having all of their model files in the same folder. I prefer a single folder for everything, including tests. It's only a couple of small tweaks to an app to support this layout, so that's what I currently do.

As for the issues you mention.

  • We already have a src/hooks folder for hooks shared between services.
  • Cross-service tests could go in the same place they are currently generated.

marshallswain avatar Dec 23 '19 01:12 marshallswain

As a reference, there already has been a long discussion related to this three years ago in https://github.com/feathersjs/generator-feathers/issues/95 (and somewhere else that I can't find at the moment). The hooks in a global folder was basically me being lazy and not wanting to figure out if it's a hook for a single or multiple services 😄

What I'd really like to have for v5 is a CLI and generator that lets you do any of those things and customize them if you want. I think I mentioned before that CLI tools and generators are notoriously thankless open source projects to maintain as a monolith providing any option anybody might want.

This is why I like the approach of http://www.hygen.io. It allows to keep the template in your project so if you want to change where the file goes, don't like the semicolons or want everything in a single file you can just change it. It could provide default or third party templates that you can install globally and if you want to change it you can "eject" the template files into your project. I'll create a follow-up issue for that in a bit.

daffl avatar Dec 23 '19 19:12 daffl

I admit I was part of the push for having models in their own separate folder, and it happened at a time of sequelize integration... but it really had little to do with ORMs. Models IMO are completely separate and independent from the services that consume them, and they [can] serve purposes outside of the context of their associated service (eg. multiple services can consume a single model). Seeing all of your models in one place also has its advantages, especially when models relate to one another (which they often do).

All that said, I don't care if the generators put models and services together. I think the "modlet" pattern is tried and true and has unspeakable advantages.

As far as global hooks, I prefer to see service-specific hooks close to my services (as they currently are) and reusable non-service-specific hooks at a more global level. For example, role and permission checks aren't the same as the roles service, but rather deal with the headers/auth attached to every service - so I'd rather see those at a global level.

DesignByOnyx avatar Dec 23 '19 21:12 DesignByOnyx

Like hooks, models can have multiple purpose, can be isolated or have relations with other ones. So why not apply the same structure to models. You can have local models related to only one service, and global models that are used by or related to multiple services or grouped together by relations.

J3m5 avatar Dec 26 '19 13:12 J3m5

Here is what I've decided to do after getting tired of seeing my modules repeat over different contexts and namespaces like

  • server.user
  • server.services.user
  • frontend.user
  • frontend.react.user etc..
src/
    modules/
       user/
           types.ts
           service.ts
           hooks.ts
           util.ts
           react.tsx

To a more advanced case
src/
    modules/
        user/
            types.ts
            service.ts
            hooks/
                  index.ts
                  mutations.ts
                  validations.ts
                  authorizations.ts
            react/
                   context.ts
                   hooks.ts
            util.ts

Then everything is sorted by having the correct imports and tree-shaking, especially taking advantage of TypeScript's import type

asasvirtuais avatar Dec 15 '21 10:12 asasvirtuais

The Feathers Dove generator will now create a typed Feathers Client for you to install/import into your front end. It's amazing how we pulled it off, mostly thanks to work by @daffl, without needing $20 million in funding like everybody else. I kid... but only a little.

You can see the client in use in https://github.com/feathersjs/feathers-chat/blob/dove/react-chat/src/feathers.ts#L7.

Also, with the Dove generator, we've switched the file structure to a more service-friendly approach, where a service's files all live together, instead of split into folders. Since we have @feathersjs/schema and resolvers, now, there's less of a need for Model-based adapters. We can focus more on adapters that don't have the Model class overhead, like Knex, MongoDB, and Memory. With the new data loader that @DaddyWarbucks is working on, I feel like we'll finally have a unified solution for populating data, removing even more dependency on Model-based adapters.

marshallswain avatar Aug 06 '22 06:08 marshallswain