|
|
| Linha 1: |
Linha 1: |
| = Fase 2 =
| |
| <br>
| |
|
| |
|
| == Escopo ==
| |
| <br>
| |
|
| |
| * Desenvolver um sistema que facilite o encontro entre pessoas que estão à procura de um quarto para alugar e as que já possuem o quarto disponível para locação em seus imóveis
| |
| * A proposta é criar uma plataforma digital (via web) que funcione como um ''matchmaking'' de moradia, similar ao funcionamento de apps de relacionamento, com base em critérios como localização, orçamento, perfil de convivência e preferências pessoais
| |
|
| |
| <br>
| |
|
| |
| == Requisitos Funcionais ==
| |
| <br>
| |
| [RF001] Implementar visualização de detalhes (quarto e perfil)
| |
|
| |
| [RF002] Implementar match
| |
|
| |
|
| |
| == Requisitos Não-Funcionais ==
| |
| <br>
| |
|
| |
| == Melhores práticas ==
| |
| <br>
| |
| <b>Single Responsibility Principle - Responsabilidade Única</b>
| |
|
| |
| A classe <code>class UserRepository(BaseRepository)</code> possui métodos de responsabilidade única como mostrado abaixo:
| |
| <pre>
| |
| def get_user_by_id(self, user_id: int) -> Optional[User]:
| |
| """Busca um usuário pelo ID."""
| |
| stmt = select(User).where(User.id == user_id)
| |
| result = self.execute_stmt(stmt)
| |
| return result.scalar_one_or_none()
| |
| </pre>
| |
| Essa função tem uma única responsabilidade que é obter o usuário do repositório não aplicando sobre o usuário nenhum tipo de regra de negócio ou modificação.
| |
|
| |
|
| |
| <b>Open/Closed Principle - Aberto para Extensão, Fechado para Modificação</b>
| |
|
| |
| A classe <code>class UserService</code> tem métodos que estão fechados para modificação mas a classe pode ser extendida adicionando novos métodos, como mostrado abaixo:
| |
|
| |
| <pre>
| |
| class UserService:
| |
| def __init__(self, user_repository: UserRepository):
| |
| self.user_repository = user_repository
| |
|
| |
| def create_user(self, name: str, email: str, senha: str, birthday: Date, profile_picture_path: str, description: str = None) -> User:
| |
| # Verificar se já existe um usuário com este e-mail
| |
| existing_user = self.user_repository.get_user_by_email(email)
| |
| if existing_user:
| |
| raise ValueError("Este e-mail já está cadastrado")
| |
|
| |
| # Hash the password before storing
| |
| hashed_password = bcrypt.hashpw(senha.encode('utf-8'), bcrypt.gensalt())
| |
| return self.user_repository.create_user(
| |
| name=name,
| |
| email=email,
| |
| senha=hashed_password.decode('utf-8'),
| |
| birthday=birthday,
| |
| profile_picture_path=profile_picture_path,
| |
| description=description
| |
| )
| |
|
| |
| def get_user_by_id(self, user_id: int) -> Optional[User]:
| |
| return self.user_repository.get_user_by_id(user_id)
| |
|
| |
| def update_user(self, user_id: int, **kwargs) -> Optional[User]:
| |
| return self.user_repository.update_user(user_id, **kwargs)
| |
|
| |
| def delete_user(self, user_id: int) -> bool:
| |
| return self.user_repository.delete_user(user_id)
| |
|
| |
| def get_user_by_email(self, email: str) -> Optional[User]:
| |
| """Busca um usuário pelo email."""
| |
| return self.user_repository.get_user_by_email(email)
| |
|
| |
| def authenticate_user(self, email: str, senha: str) -> Optional[User]:
| |
| """Autentica um usuário verificando email e senha"""
| |
| user = self.user_repository.get_user_by_email(email)
| |
| if not user:
| |
| return None
| |
|
| |
| if not bcrypt.checkpw(senha.encode('utf-8'), user.senha.encode('utf-8')):
| |
| return None
| |
|
| |
| return user
| |
| </pre>
| |
|
| |
|
| |
| <b>Liskov Substitution Principle - Substituição de Liskov</b>
| |
|
| |
| Todas as classes que fazem parte de um repositório herdam/implementam <code>BaseRepository</code>, como exemplo temos a classe <code>UserRepository</code>.
| |
|
| |
| <pre>
| |
| class UserRepository(BaseRepository):
| |
| def __init__(self, session: Session):
| |
| super().__init__(session)
| |
|
| |
| class BaseRepository:
| |
| """
| |
| Repositório base que recebe uma sessão como dependência.
| |
| Segue o princípio de Inversão de Dependência.
| |
| """
| |
|
| |
| def __init__(self, session: Session):
| |
| """
| |
| Inicializa o repositório com uma sessão do banco de dados.
| |
|
| |
| Args:
| |
| session: Sessão do SQLAlchemy gerenciada externamente
| |
| """
| |
| self.session = session
| |
|
| |
| def execute_stmt(self, stmt: Any):
| |
| """
| |
| Executa um statement SQLAlchemy usando a sessão injetada.
| |
|
| |
| Args:
| |
| stmt: Statement SQLAlchemy (select, insert, update, delete, etc.)
| |
|
| |
| Returns:
| |
| Resultado da execução do statement
| |
| """
| |
| return self.session.execute(stmt)
| |
| </pre>
| |
|
| |
|
| |
| <b>Interface Segregation Principle - Segregação de Interfaces</b>
| |
|
| |
| A linguagem Python não implementa interfaces que expõe métodos, com isso não foi possível aplicar esse princípio no projeto
| |
|
| |
|
| |
| <b>Dependency Inversion Principle - Inversão de Dependência</b>
| |
|
| |
| Mesmo sem a presença se interfaces o que facilita a inversão de depedência, conseguimos aplicar este princípio criando um classe referente a repositório que faz a instanciação do banco de dados assim que a classe é criada não sendo necessário repetir o código novamente.
| |
|
| |
| <pre>
| |
| class UserRepository(BaseRepository):
| |
| def __init__(self, session: Session):
| |
| super().__init__(session)
| |
|
| |
| class BaseRepository:
| |
| """
| |
| Repositório base que recebe uma sessão como dependência.
| |
| Segue o princípio de Inversão de Dependência.
| |
| """
| |
|
| |
| def __init__(self, session: Session):
| |
| """
| |
| Inicializa o repositório com uma sessão do banco de dados.
| |
|
| |
| Args:
| |
| session: Sessão do SQLAlchemy gerenciada externamente
| |
| """
| |
| self.session = session
| |
|
| |
| def execute_stmt(self, stmt: Any):
| |
| """
| |
| Executa um statement SQLAlchemy usando a sessão injetada.
| |
|
| |
| Args:
| |
| stmt: Statement SQLAlchemy (select, insert, update, delete, etc.)
| |
|
| |
| Returns:
| |
| Resultado da execução do statement
| |
| """
| |
| return self.session.execute(stmt)
| |
| </pre>
| |
|
| |
|
| |
| <b>Clean Code</b>
| |
| O código foi pensado para possuir métodos simples e fáceis de entender e dar manutenção, além de possuir variáveis com nomes que refletem as propriedades do objeto facilitando assim o entendimento da lógica do código.
| |
|
| |
| = Evolução do projeto =
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! Item !! Data !! Atividades Room Match !! Realizado
| |
| |-
| |
| | 1 || 14/11/2025 || Documentar tópico Investigação || 0%
| |
| |-
| |
| | 2 || 14/11/2025 || Definir Proposta de Projeto || 0%
| |
| |-
| |
| | 3 || 14/11/2025 || Validar Visão do Usuário || 0%
| |
| |-
| |
| | 4 || 14/11/2025 || Especificar RFs e RNFs - Fase 2 || 100%
| |
| |-
| |
| | 5 || 17/11/2025 || RF01: Implementar visualização de detalhes || 25%
| |
| |-
| |
| | x || 24/11/2025 || TeckWeek ||
| |
| |-
| |
| | 6 || 01/12/2025 || Melhores Práticas ||
| |
| |-
| |
| | 7 || 01/12/2025 || RF01: Implementar visualização de detalhes ||
| |
| |-
| |
| | 8 || 01/12/2025 || RF02: Implementar match ||
| |
| |-
| |
| | 9 || || Desenvolver 3o RF ||
| |
| |-
| |
| | 10 || || Desenvolver 4o RF ||
| |
| |-
| |
| | 11 || || Incrementar diferencial tecnológico ||
| |
| |-
| |
| |}
| |