Bussines Rules

Conforme as regras de negócio foram crescendo, o código do UseCase foi ficando mais complexo, difícil de testar e muitas vezes até duplicado entre os métodos do UseCase. Para contornar este problema, desenvolvemos o BussinessRules com o objetivo de organizar as regras de negócio, remover código duplicado e simplificar os testes unitários.

Segue abaixo exemplo da implementação do BussinessRules.

import pendulum as datetime

from itflex.bussiness import BussinessRules
from itflex.common.response import Status
from itflex.repo import SQLRepoBase
from itflex_auth.entities import User
from itflex_auth.users.requests import UpdateUser


def get_user(buss: BussinessRules, repo: SQLRepoBase, id: int):
    resp = repo.get_by_id(id)
    if resp.ok:
        buss.user = resp.item
        return

    buss.add_error(status=Status.not_found)
    buss.exec_continue = False


def update_user(buss: BussinessRules, repo: SQLRepoBase, req: UpdateUser):
    updated_at = datetime.now()

    user = buss.user.replace(req, updated_at=updated_at)
    resp = repo.update(user)
    if resp.ok:
        return

    buss.add_error(status=resp.status, errors=resp.errors)
    buss.exec_continue = False


class UsersBussiness(BussinessRules):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.user: User = None

        self.add_method(get_user, "uc.repo", "req.id")
        self.add_method(update_user, "uc.repo", "req")

Se você observar as funções são pequenas e cada função é responsável por apenas uma regra. As regras são construídas desta forma, para facilitar a sua leitura, e a escrita dos testes unitários.

Segue abaixo o exemplo utilizando o BussinessRules, no método update do UseCase.

class UsersUC(BaseUC):

    @register_request(UpdateUser)
    def update(self, req: UpdateUser) -> ItemResp:
        buss = (
            UsersBussiness(uc=self, req=req)
            .get_user()
            .update_user()
            .get_user()
        )

        if not buss.ok:
            return buss.response

        user_audit(self.audit, req.consumer, buss.user, "update")
        self.events.updated(buss.user)
        return ItemResp(item=buss.user)

Se você observar no update, foi instanciado o UsersBussiness passando a referência do UseCase e o request com as informações do usuário para atualizar.

E na sequência foi chamado as regras na ordem correta de execução. Que no caso do update é:

  • Buscar o usuário que vai ser atualizado.
  • Atualizar o usuário no banco.
  • Buscar o usuário novamente com os dados atualizados.

Detalhe importante, em relação aos erros. O BussinessRules padroniza e armazena as mensagens de erros, se alguma regra falhar, o buss.ok será igual a falso e o buss.response será o retorno do método update com as mensagens de erros.