使用NestJS进行功能分组

huangapple go评论78阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年7月6日 20:33:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76628890.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定