英文:
Feature grouping with NestJS
问题
我们正在开发一个多租户应用,但我遇到了一个情况,需要经常使用forwardRef,这在NestJS的文档中被称为代码异味的一种表现。该应用程序中的模块示例包括:app,auth,company,paymet,projectc,survey,search,tenant和user(实际上还有更多)。
每个模块都有自己的服务(也称为提供者),模型等。我们正在使用Prisma,因此对于典型的crud方法,我们没有单独的文件,它们位于服务本身内部。
为什么需要使用forward ref 的示例
租户模块
@Module({
imports: [PaymentModule],
providers: [TenantService],
})
export class TenantModule {}
租户服务
@Injectable()
export class TenantService {
async get(tenantId: number) {
return prisma.tenant.findFirst({ where: { id: tenantId } });
}
async create(data) {
// ... logic
const tenantId = generateId();
await PaymentService.createCustomer(tenantId)
// ... logic
}
}
付款模块
@Module({
imports: [TenantModule],
providers: [PaymentService],
})
export class PaymentModule {}
付款服务
@Injectable()
export class PaymentService {
async createCustomer(tenantId) {
// ... logic
}
async charge(tenantId: number) {
const tenant = await this.tenantService.get(tenantId);
// ... logic
}
}
问题
我的问题是我们应该如何调整结构以实现更好的“特性分组”。例如,我们目前在许多其他模块中使用了租户服务,但我不认为它是一个“特性”。任何指导、提示、链接或有助于的文档都是非常欢迎的。我真的看不出还有其他做法,也找不到好的示例。
英文:
We are developing a multi-tenant application but I'm running into a situation where I need to use forwardRef quite often which would indicate a code smell as mentioned in the docs of NestJS. Example of modules in this applications are: app, auth, company, paymet, projectc, survey, search, tenant and user (there are more in reality).
Each module has their own service (aka provider), model, etc. We are using Prisma so we don't have a separate file for the typical crud methods and they are located inside the service itself.
Example of why forward ref is needed
Tenant module
@Module({
imports: [PaymentModule],
providers: [TenantService],
})
export class TenantModule {}
Tenant service
@Injectable()
export class TenantService {
async get(tenantId: number) {
return prisma.tenant.findFirst({ where: { id: tenantId } });
}
async create(data) {
// ... logic
const tenantId = generateId();
await PaymentService.createCustomer(tenantId)
// ... logic
}
}
Payment module
@Module({
imports: [TenantModule],
providers: [PaymentService],
})
export class PaymentModule {}
Payment service
@Injectable()
export class PaymentService {
async createCustomer(tenantId) {
// ... logic
}
async charge(tenantId: number) {
const tenant = await this.tenantService.get(tenantId);
// ... logic
}
}
Question
My question is how should we adjust our structure to be more "feature grouping". Currently for example we are using the tenant service in a lot of the other modules and I don't see how it would be a "feature". Any guidance, tips, links, documents that would help are highly welcome. I don't really see another way of doing this and can't find good examples either.
答案1
得分: 1
你可能应该有另一个处理你的逻辑的模块。
我们可以想象一个SuperFunctionnalityModule,它有自己的控制器/服务,看起来像这样,跟随你的代码:
//...正确的类声明
async createTenantForFunctionnality(data) {
const tenantId = TenantService.generateId();
await PaymentService.createCustomer(tenantId)
}
因此,每个服务只处理自己的逻辑,你的功能/应用相关模块会启动它们。
另外,一些模块可能会全局声明/注册(参见 https://docs.nestjs.com/modules#global-modules),这可能适用于你的身份验证模块。
英文:
You should probably have another module that handles your logic.
We could imagine a SuperFunctionnalityModule, with its own controller/service that would look likes this, following your code:
//...correct class declaration
async createTenantForFunctionnality(data) {
const tenantId = TenantService.generateId();
await PaymentService.createCustomer(tenantId)
}
Thus, each service only deals with its own logic, and your functionality/app-related module bootstraps it all.
Also, some modules might be declared/register globally (see https://docs.nestjs.com/modules#global-modules), its probably the case for your auth module.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论