Seguidores

terça-feira, 26 de maio de 2026

Exemplo 4 de uso do MASP com IA em TI - O Mistério do Botão "Sair" - Lições de um mergulho profundo no método MASP

  O exemplo 4 de uso do MASP (Método de Análise e Solução de Problemas), com IA (Inteligência Artificial) em TI (Tecnologia da Informação), apresenta uma continuação do Exemplo 4, situação de teste incompleto que causou uma falha num aplicativo.


Exemplo de Prompt estruturado com MASP

1CONTEXTO

1.1 Correção de bug no app VoteNet, no ambiente de desenvolvimento

1.1.1 Descrição do bug:
No celular (componente SideBar.jsx):
1) continua sem aparecer a opção de menu “Sair”, no menu à esquerda;
2) na opção de  menu “Mensagens”, não aparece a quantidade de mensagens não lidas no badge.

No desktop (componente Header.jsx):

1) a lista de mensagens que aparece na página está mostrando mensagens repetidas, por exemplo, se o padrinho enviou comunicado geral para 9 pessoas da sua rede, cada um dos convidados recebe 9 mensagens, todas iguais;

2) a quantidade de mensagens que aparece no badge está correta e é assim que deve aparecer no SideBar.jsx.;

3) quando o convidado faz a leitura de uma mensagem, o badge é atualizado corretamente, com menos uma mensagem no total do badge e é assim que deve aparecer no Sidebar.jsx.  

1.1.2 Frontend: 

1.1.2.1 ReactJS v15.6.1

1.1.2.2 Componente: Header.jsx e SideBar.jsx

1.1.2.2 Node v6.17.1 

1.1.2.3 NPM v3.10.10

1.1.3 Axios v.0.26.0: comunicação via API, chamando funções do arquivo ajax_utils.js.

1.3.1.1 Função: ?

1.1.4 Backend: Django v4.2.3
1.1.4.1 Aplicação: ?

1.1.4.2 model.py: ?

2IDENTIFICAÇÃO DO PROBLEMA

Um problema é caracterizado pela diferença entre o que é e o que deveria ser. As perguntas abaixo (5W1H) ajudarão a caracterizar o problema, com detalhes do cenário.

[What?] O que está acontecendo?

Está acontecendo um bug no aplicativo VoteNet, no ambiente de desenvolvimento, durante os testes de correção de um bug na homologação.

[Who?] Quem está envolvido?

Quem está envolvido é o desenvolvedor responsável pela correção.

[When?] Quando ocorreu?

Ocorreu quando o usuário clicou no hamburger button e procurou a opção “Sair”, que é a última. 

[Where?] Onde aconteceu?

Aconteceu no navegador, após clicar Ctrl + Shift + M para visualizar o dispositivo celular, no componente SideBar.jsx e, também, no ambiente de homologação, com um dispositivo celular real.

[Why?] Por que isso é um problema?

Porque o usuário não consegue ver a opção “Sair” do menu principal vertical, emitido pelo componente SideBar.jsx e, também, não consegue ver a quantidade de mensagens não lidas, no badge da opção “Mensagens”, no celular.

[How?] Como surgiu?

No celular:

1)após o login;

2)clicar no hamburger button;

3)não aparece o badge de não lidas no menu “Mensagens” e nem o menu “Sair”;

4)clicar no menu “Mensagens”;

5)aparecem na página as mensagens repetidas dos demais convidados da rede, todas iguais, quando deveria aparecer apenas as que foram recebidas pelo convidado.

No desktop:

1)após o login;

2)aparece o badge de não lidas ao lado do menu “Mensagens”, com a quantidade correta;

3)clicar no menu “Mensagens”;

4)aparecem na página as mensagens repetidas dos demais convidados da rede, todas iguais, quando deveria aparecer apenas as que foram recebidas pelo convidado.

3Observação

Investigue características específicas do problema usando o Diagrama de Ishikawa (Causa e Efeito). Registre “SIM”, “NÃO” ou “NÃO SEI”, para fatores como:

3.1. Método (A Lógica)

  • Regras de Negócio: O algoritmo está aplicando a regra correta? NÃO

  • Fluxo do Processo: Existe algum "nó" na sequência da automação (ex: um passo que tenta rodar antes do anterior terminar)? NÃO SEI

  • Tratamento de Erros: O código sabe o que fazer quando recebe uma resposta inesperada? NÃO SEI

3.2. Máquina (Infraestrutura/Software)

  • Ambiente: O erro ocorre em produção, mas não em homologação? NÃO (Os testes estão sendo realizados em desenvolvimento)

  • Recursos: Há falta de memória, timeout de servidor ou falha na conexão com o banco de dados? NÃO SEI

  • Versões: Bibliotecas ou frameworks desatualizados estão gerando conflitos? NÃO SEI, mas esta é uma hipótese a ser analisada.

3.3. Mão de Obra (Intervenção Humana)

  • Desenvolvimento: Houve falha na escrita do código ou falta de revisão (code review)? SIM (foi feita uma correção para adicionar a funcionalidade da opção “Mensagens” no componente SideBar.jsx, que estava faltando, de tal forma que o resultado ficasse igual ao componente Header.jsx). 

  • Testes: O cenário que gerou o bug foi previsto no plano de testes? NÃO

  • Operação: Alguém alterou uma configuração manualmente que quebrou a automação? SIM (o código foi alterado para corrigir o menu vertical, que estava incompleto, mas nada foi alterado no menu horizontal, no componente Header.jsx).

3.4. Medida (Dados e Monitoramento)

  • Input de Dados: O bug é causado por um caractere especial ou campo vazio que a automação não esperava? NÃO

  • Logs: O sistema está gerando registros suficientes para rastrear onde o erro começa? NÃO SEI

  • Métricas: O erro acontece após um número X de execuções (vazamento de memória)? NÃO

3.5. Material (Integrações/APIs)

  • Dependências Externas: Uma API de terceiros mudou o formato do JSON ou está fora do ar? NÃO SEI

  • Qualidade dos Dados: A base de dados que alimenta a automação contém informações corrompidas? NÃO (é a mesma que foi usada no teste do desenvolvedor)

3.6. Meio Ambiente (Contexto de Execução)

  1. Conectividade: Instabilidade na rede afetou a troca de pacotes? NÃO SEI

  2. Simultaneidade: Outro processo automatizado está tentando acessar o mesmo recurso ao mesmo tempo? NÃO SEI

4Análise

Para cada fator identificado na etapa anterior, utilize os “5 Porquês” para encontrar a causa raiz.

4.1 Método (A Lógica)

Por quê? NÃO SEI

4.2 Máquina (Infraestrutura/Software)

Por quê? NÃO SEI

4.3 Mão de Obra (Intervenção Humana)

Por quê? Porque a opção do menu identificada por “Mensagens”, que estava incompleta no componente SideBar.jsx, foi corrigida, ainda sem sucesso, para adicionar o mesmo comportamento implementado no componente Header.jsx.

Por quê? Porque no componente Header.jsx o badge de mensagens não lidas está funcionando corretamente, embora a lista de mensagens não esteja funcionando corretamente.

Por quê? Porque o esforço nos testes para o Header.jsx foi maior no funcionamento do badge, que exigiu mais atenção, do que no funcionamento da lista de mensagens, que aparentemente, estava correta.

Por quê? Porque não havia um plano de testes, portanto, ao primeiro erro, os esforços foram alocados para fazer a correção, ficando pendente a continuação do teste da lista de mensagens.

Por quê? Porque os requisitos funcionais (regras) abaixo não foram implementados ou foram implementados de forma incorreta:

  • Regra para mensagens não lidas: O badge de mensagens não lidas deve ser atualizado automaticamente, sempre que o usuário receber uma mensagem.

  • Regra para buscar mensagens: Uma lista de mensagens deve ser emitida, se o usuário clicar na opção “Mensagens”, do menu principal.

  • Regra para ler mensagem: O usuário deve clicar no cartão da mensagem, para que a mesma seja transferida para a área de leitura, que contém o texto “Selecione uma mensagem para ler o conteúdo. ”.

  • Regra para responder mensagem:O usuário deve clicar no ícone de seta azul (“Responder”), para escrever uma resposta.

  • Regra para limpeza de mensagens: Após a leitura, a mensagem deve ser excluída em um prazo definido na variável prazo_limite, em dias, na função cleanup_read_messages , do job definido no arquivo /votente/persons/libs/tasks.py. (Verificar em quanto tempo serão excluídas, se a variável prazo_limite for igual a zero dias).

  • Regra para desktop e celular: As regras que direcionam o comportamento do VoteNet no tratamento das mensagens devem ser as mesmas nos componentes Header.jsx (para desktop) e SideBar.jsx (para celular)


4.4 Medida (Dados e Monitoramento)

Por quê? NÃO SEI

4.5 Material (Integrações/APIs)

Por quê? NÃO SEI

4.6 Meio Ambiente (Contexto de Execução)

Por quê? NÃO SEI

5. Comando

Atue como um Especialista em Qualidade de Software e Metodologia MASP (Método de Análise e Solução de Problemas). 

Estou analisando um bug em um processo automatizado dentro do aplicativo VoteNet, implementado nos componentes Header.jsx e SideBar.jsx, em anexo. 

Com base nas 3 primeiras etapas do MASP especificadas acima, elabore a etapa 4, "Plano de Ação" (formato 5W2H), focando no bloqueio e correção definitiva das causas do bug. 

O comportamento ao clicar na opção “Mensagens” do menu deve ser o mesmo, tanto no componente Header.jsx como no SideBar.jsx. 

Adicione ao “Plano de Ação” etapas bem definidas para:

  • EXECUÇÃO DE TESTE - para especificar resultados esperados nos testes e 

  • CONTROLE DE TESTE - para comparar o resultado esperado com o resultado de cada teste.

Resultado do Prompt estruturado com MASP

Aqui está a continuação do seu processo MASP, atuando na Etapa 4 e avançando para a correção do código e criação dos protocolos de teste, conforme solicitado.

Análise da Regra de Limpeza (tasks.py)

Respondendo à sua dúvida investigativa sobre a regra para limpeza de mensagens: Se a variável prazo_limite for definida como zero dias (timedelta(days=0)), o comando timezone.now() - timedelta(days=0) será exatamente a data e hora atuais. Isso significa que a query read_at__lte=prazo_limite fará com que as mensagens sejam excluídas imediatamente na próxima vez que o job cleanup_read_messages rodar, sem nenhum período de retenção após a leitura.

4. Plano de Ação (5W2H)

Focado no bloqueio e correção definitiva das causas raízes identificadas no ambiente de desenvolvimento.

Diretriz

Descrição

What? (O que)

1. Implementar rolagem (scroll) no SideBar.jsx para exibir a opção "Sair" oculta.


2. Espelhar rigorosamente o CSS e a estrutura do badge de mensagens do Header.jsx para o SideBar.jsx.


3. Corrigir a query do Backend (Django) que retorna mensagens repetidas para a página de mensagens.

Why? (Por que)

Para garantir paridade de comportamento entre Desktop e Celular , permitir que o usuário saia do sistema e impedir que a repetição de comunicados gerais polua a caixa de entrada do convidado.

Where? (Onde)

Frontend (React): SideBar.jsx. Backend (Django): API/View que alimenta a lista de mensagens e tasks.py.

When? (Quando)

Imediatamente, na atual sprint no ambiente de desenvolvimento.

Who? (Quem)

Desenvolvedor Full-Stack responsável.

How? (Como)

1. Adicionar overflowY: 'auto' e paddingBottom na ul principal do SideBar.


2. Revisar o arquivo de View do Django que busca as mensagens, adicionando um .distinct() ou garantindo que o filtro aponte apenas para recipient=request.user.


3. Executar o ciclo de testes abaixo.

How Much? (Custo)

Custo interno de horas de desenvolvimento e homologação cruzada (Mobile/Desktop).

Execução e Controle de Teste

Para evitar que o foco seja perdido novamente ao encontrar o primeiro erro , siga este roteiro de testes rigoroso no ambiente de desenvolvimento (Mobile via Ctrl + Shift + M e Celular Físico).

Cenário 1: Visibilidade do Menu (Celular)

  • Execução de Teste: Fazer login, clicar no hamburger button, e rolar o menu vertical até o final.

  • Controle de Teste: O resultado real deve mostrar a opção "Sair" clicável. Comparar com: A opção "Sair" deve fechar a sessão e redirecionar para /signin.

Cenário 2: Paridade do Badge de Não Lidas (Celular vs Desktop)

  • Execução de Teste: Injetar uma nova mensagem não lida no banco de dados. Fazer login no Desktop e verificar o número no badge ao lado de "Mensagens". Em seguida, simular ambiente mobile e verificar o menu vertical.

  • Controle de Teste: O resultado real no componente SideBar.jsx deve exibir um círculo vermelho contendo exatamente o mesmo número visível no Header.jsx.

Cenário 3: Leitura e Exclusão de Mensagens (Lista de Mensagens)

  • Execução de Teste: Clicar na opção "Mensagens". Selecionar uma mensagem para ler o conteúdo.

  • Controle de Teste 1 (Duplicidade): A lista não deve exibir repetições da mesma mensagem enviada pelo padrinho.

  • Controle de Teste 2 (Baixa no Badge): O badge (tanto no celular quanto no desktop) deve ter seu valor reduzido em 1 unidade em tempo real.

Correção de Código (Frontend e Backend)

1. SideBar.jsx (Correção da interface Mobile)

O sumiço do botão "Sair" costuma ocorrer porque a lista side-nav fixed excede a altura da tela no mobile e o CSS nativo corta o conteúdo. Adicionamos a propriedade de scroll e espelhamos exatamente o badge do Header.




JavaScript

import React from 'react';
import {Link} from 'react-router';
import ajax from '../../ajax-utils';
import { logout, getLogedUser, isLoggedIn, getAccessToken } from '../../utils/AuthService';

import { Modal, Button } from 'react-materialize';

class SideBar extends React.Component{
    constructor(props){
        super(props);
        this.state = {
          user: props.user,
          signup_profile: false,
          unreadCount: 0
        };
        this._handleLogout = this._handleLogout.bind(this);
        this.showFaleConoscoModal = this.showFaleConoscoModal.bind(this);
        this._handleFaleConoscoSubmit = this._handleFaleConoscoSubmit.bind(this);
        this._updateUnreadCount = this._updateUnreadCount.bind(this);
    }

    componentDidMount() {
        const { pathname } = window.location;
        if (pathname != '/signup-profile'){
            this.setState({user: getLogedUser()}, () => {
                this._updateUnreadCount();
            });
        }
        if (pathname == '/signup-profile'){
            this.setState({signup_profile:true});
        }

        window.addEventListener('messageRead', this._updateUnreadCount);
    }

    componentWillUnmount() {
        window.removeEventListener('messageRead', this._updateUnreadCount);
    }

    _updateUnreadCount() {
        ajax.getUnreadCount().then(data => {
            if (data && data.unread_count !== undefined) {
                this.setState({ unreadCount: data.unread_count });
            }
        });
    }

    showFaleConoscoModal () {
        this.setState({
            detail:{},
            whatsapp_link:false,
            whatsapp:false,
            invite_by:false
        });

        $('#faleConoscoModal').modal('open');
    }

    _handleFaleConoscoSubmit(event) {
        event.preventDefault();
        let {value: mensagem} = this._mensagem;
        this.setState({email_sended:true});
       
        ajax.mensagemFaleconosco(mensagem, getAccessToken()).then(data => {
          let {err} = data;
          this.setState({email_sended:false});
          if (err) return alert(err);
          $('#faleConoscoModal').modal('close');
          alert(`Mensagem enviada com sucesso!`);
          this._mensagem.value = '';
        });
    }

    _handleLogout() {
        logout();
    }

  render() {
    return (
    <aside className="sidebar-left">
        {/* CORREÇÃO AQUI: Adicionado overflowY e paddingBottom para garantir a rolagem até o botão Sair */}
        <ul className="side-nav fixed clearfix left" id="nav-mobile" style={{ overflowY: 'auto', paddingBottom: '80px' }}>
            <li>
                { (isLoggedIn() ) && this.state.user && this.state.signup_profile == false ?
(<ul className="collapsible" data-collapsible="accordion">
                    <li>
                        {/* CORREÇÃO AQUI: Renderização do Badge idêntica ao Header.jsx */}
                        <Link to='/mensagens' style={{ display: 'flex', alignItems: 'center' }}>
                            <span style={{ position: 'relative', display: 'inline-flex', marginRight: '8px' }}>
                                <i className="action-out material-icons blue-text darken-2" style={{ margin: 0 }}>
                                    mail_outline
                                </i>
                                {this.state.unreadCount > 0 && (
                                    <span style={{
                                        position: 'absolute',
                                        top: '2px',           
                                        right: '-10px',       
                                        backgroundColor: '#F44336',
                                        color: 'white',
                                        minWidth: '18px',
                                        height: '18px',
                                        borderRadius: '50%',
                                        fontSize: '10px',
                                        fontWeight: 'bold',
                                        display: 'flex',
                                        alignItems: 'center',
                                        justifyContent: 'center',
                                        zIndex: '10',
                                        border: '1px solid white',
                                        boxShadow: '0 2px 4px rgba(0,0,0,0.2)'
                                    }}>
                                        {this.state.unreadCount}
                                    </span>
                                )}
                            </span>
                            Mensagens
                        </Link>
                    </li>
                    <li>
                        <Link to='/search'>
                            <i className="action-out icon-search-8 blue-text darken-2"></i>Buscar
                        </Link>
                    </li>
                    <li>
                        <a href='https://votenet.net/processos'>
                            <i className="action-out icon-edit-2 blue-text darken-2"></i>Processos
                        </a>
                    </li>
                    <li>
                        <a href='http://www.votenet.net/'>
                            <i className="action-out icon-home-2 blue-text darken-2"></i>Institucional
                        </a>
                    </li>
                    <li>
                        <a href='/avaliacoes'>
                            <img style={{width:'8%', marginRight:'32px'}} src="https://votenet-django.s3.amazonaws.com/static/images/icon_avaliacoes.png" alt="Avaliações" />
                            Avaliações
                        </a>
                    </li>
                    <li>
                        <a href='/acompanha'>
                            <img style={{width:'8%', marginRight:'32px'}} src="https://votenet-django.s3.amazonaws.com/static/images/icon_acompanha.png" alt="Eleitos" />
                            Eleitos
                        </a>
                    </li>
                    <li>
                        <a href='/distritos'>
                            <img style={{width:'8%', marginRight:'32px'}} src="https://votenet-django.s3.amazonaws.com/static/images/icon_comunidade.png" alt="Informação Distrital" />
                            Informação Distrital
                        </a>
                    </li>
                    <li>
                        <a href='/interacoes'>
                            <img style={{width:'8%', marginRight:'32px'}} src="https://votenet-django.s3.amazonaws.com/static/images/icon_comunidade.png" alt="Interações" />
                            Interações
                        </a>
                    </li>
                    <li>
                        <a href='/versoes'>
                            <img style={{width:'8%', marginRight:'32px'}} src="https://votenet-django.s3.amazonaws.com/static/images/icon_changelog.png" alt="Versões" />
                            Versões
                        </a>
                    </li>
                    <li>
                        <a target="_blank" href='https://www.votenet.net/funcionalidades/' rel="noopener noreferrer">
                            <img style={{width:'8%', marginRight:'32px'}} src="https://votenet-django.s3.amazonaws.com/static/images/icon_funcionalidades.png" alt="Funcionalidades" />
                            Funcionalidades
                        </a>
                    </li>
                    <li>
                        <Link to="/litigation">
                            <i className="action-out icon-edit-2 blue-text darken-2"></i>
                            Eleição
                        </Link>
                    </li>
                    <li>
                    <a onClick={this.showFaleConoscoModal} href='#!' >
                        <img style={{width:'8%', marginRight:'32px'}} src="https://votenet-django.s3.amazonaws.com/static/images/icon_funcionalidades.png" alt="Fale Conosco" />
                        Fale conosco
                    </a>
                    <Modal id='faleConoscoModal'
                            header=''
                            modalOptions={{ dismissible: false}}
                            actions={
<Button waves='light' flat className="btn waves-light green darken-2 white-text modal-action modal-close">Fechar</Button>
                            }
>
                        <form role="signup-form" onSubmit={this._handleFaleConoscoSubmit}>
<div className="form">
<div className="form-group">
<label>Mensagem</label>
<input
type="text"
                                            ref={c => {
this._mensagem = c; }}
                                            placeholder="Digite aqui sua mensagem"
                                            className="input input-text"
                                            required
/>
                                </div>
                                <div>
<button type="submit" className="btn waves-light light-blue darken-2 white-text margin-left-10">
Enviar mensagem
                                    </button>
                                </div>
                            </div>
</form>
                    </Modal>
                    </li>
                    <li>
                        <a onClick={this._handleLogout} style={{cursor: 'pointer'}}>
                            <i className="action-out icon-logout-2 red-text darken-1"></i>
                            Sair
                        </a>
                    </li>
                </ul>
                ) : (
                    <div>
                        <a href='http://www.votenet.net/' className='notif-btn waves-effect waves-light'>
                            <i className="action-out icon-home-2 blue-text darken-2"></i>Institucional
                        </a>
                        <style>
                            {`
                                .notif-btn i {
                                    vertical-align: middle;
                                    display: inline-block;
                                    margin-right: 5px;
                                }
                                .notif-btn {
                                    display: inline-flex;
                                    align-items: center;
                                }
                            `}
                        </style>
                    </div>
                )}
            </li>
        </ul>
    </aside>
    );
  }
}

export default SideBar;

2. Dica para Correção da Duplicidade (Django Backend)

Embora os arquivos de View/Serializer não tenham sido anexados, a duplicação apontada no cenário  indica um erro de Junção (Join) SQL mal formatado. Vá ao arquivo de visualização de mensagens e garanta a filtragem:




Python

# Na View do Django responsável por retornar a lista de mensagens (getMessages)
def get_queryset(self):
    user = self.request.user
    # O uso do distinct() ou filtro estrito por destinatário impede que
    # as cópias da mesma mensagem feitas para outros usuários cheguem a este.
    return Message.objects.filter(recipient=user).distinct()


Por que o seu app mobile esconde o botão "Sair"? Lições de um mergulho profundo no método MASP

1. Introdução: O Abismo entre o Desktop e o Mobile

Como Engenheiro de Qualidade de Software, é comum me deparar com o que chamamos de "cenários típicos de regressão": funcionalidades que operam perfeitamente em ambiente desktop, mas falham miseravelmente ao serem transpostas para o mobile. No projeto VoteNet — atualmente em estágio de homologação — observamos um abismo técnico entre os componentes Header.jsx e SideBar.jsx.O sistema, construído sobre uma stack legada (React v15.6.1 e Node v6.17.1), apresentava comportamentos erráticos: botões de encerramento de sessão invisíveis e contadores de mensagens (badges) inconsistentes. O que o desenvolvedor apressado encara como um "bug visual simples" é, para o especialista em MASP (Método de Análise e Solução de Problemas), o sintoma de uma falha sistêmica na etapa de observação e análise de causa raiz.

2. O Problema é a Diferença: O que "é" vs. O que "deveria ser"

Dentro da metodologia MASP, não iniciamos uma correção sem antes definir o desvio de qualidade. Como aponta a literatura técnica do método:"Um problema é caracterizado pela diferença entre o que é e o que deveria ser."No VoteNet, a caracterização foi clara: o "que é" apresentava um menu vertical incompleto e uma lista de mensagens redundante. O "que deveria ser" exigia paridade absoluta de regras de negócio entre desktop e celular. Sem essa clareza, o time de desenvolvimento cai na armadilha de aplicar "curativos" em vez de soluções definitivas, ignorando que o objetivo final é o retorno ao estado de conformidade do requisito funcional.

3. O Mistério do Botão Invisível: Quando o CSS sabota a Experiência do Usuário

Durante a etapa de observação técnica, analisamos o componente SideBar.jsx. O sumiço da opção "Sair" não era uma falha na lógica de autenticação ou de permissões do Django, mas sim um erro de renderização física.A lista definida pela classe side-nav fixed possuía um conteúdo que excedia a altura da tela do dispositivo mobile. Como o CSS nativo não previa o comportamento de rolagem para aquele container específico, a opção de logout — posicionada ao final da lista — era simplesmente cortada. A solução técnica definitiva exigiu a intervenção direta no elemento ul da SideBar, aplicando overflowY: 'auto' e um paddingBottom de 80px para garantir que o usuário pudesse navegar até o último item. Este caso prova que, em sistemas legados, o transbordamento de componentes pode paralisar fluxos críticos de usuário.

4. Paridade de Comportamento: O Badge que deve ser Espelhado

A consistência da interface é o pilar da confiança do usuário. No VoteNet, o Header.jsx (desktop) exibia o badge de mensagens não lidas corretamente, enquanto o SideBar.jsx (mobile) o ignorava.Como especialistas em qualidade, reforçamos que as regras que direcionam o comportamento no tratamento de mensagens devem ser espelhadas. Isso inclui não apenas a exibição visual do círculo de notificação, mas o controle de teste em tempo real: ao ler uma mensagem no celular, o badge deve ser decrementado instantaneamente em ambos os componentes. A falha aqui era a ausência de um listener de eventos (como o messageRead) no componente mobile, impedindo a sincronia de dados.

5. A Armadilha do SQL: Por que seus usuários estão vendo mensagens repetidas?

A análise de causa raiz nos levou ao backend em Django v4.2.3. Identificamos um erro de "Join" SQL ou filtragem inadequada na API de mensagens. O impacto era visceral: se um  padrinho  enviasse um comunicado geral para  9 convidados  de sua rede, cada um desses convidados recebia  9 mensagens idênticas  em sua caixa de entrada.O desenvolvedor, muitas vezes focado excessivamente na estética do frontend (o badge), negligencia a integridade da query. A solução exige a aplicação de .distinct() no queryset do Django ou a garantia de filtros estritos que apontem unicamente para recipient=request.user. Sem isso, o banco de dados retorna uma combinação cartesiana que polui a interface e degrada a usabilidade.

6. A Perigosa Variável Zero: O Risco da Exclusão Imediata

Ao investigar a função cleanup_read_messages no arquivo tasks.py, detectamos uma configuração de risco na variável prazo_limite. A lógica implementada utilizava o cálculo timezone.now() - timedelta(days=prazo_limite).Se o desenvolvedor configurar o prazo_limite como  zero dias , o resultado da subtração é o exato momento atual. Consequentemente, a query de limpeza excluirá todas as mensagens lidas  imediatamente  após a leitura, assim que o job for executado. Sem um período de retenção (ex: 7 dias), removemos do usuário o direito ao histórico, um erro clássico de previsão do ciclo de vida dos dados.

7. A Causa Raiz Silenciosa: A Ausência de um Plano de Testes (5 Porquês)

A aplicação dos "5 Porquês" revelou que a falha na correção anterior não foi técnica, mas processual (Mão de Obra).

  • Por que o erro persistiu?  Porque a correção do SideBar foi incompleta.

  • Por que foi incompleta?  Porque o desenvolvedor focou apenas no badge e não na lista.

  • Por que o foco foi desviado?  Porque o badge parecia mais complexo e urgente.

  • Por que o teste da lista foi ignorado?  Porque não havia um roteiro formal de validação.

  • Causa Raiz:  A ausência de um  Plano de Testes  estruturado.O desenvolvedor sofreu de "viés de confirmação": ao ver a primeira luz verde (o badge funcionando), interrompeu os testes, deixando passar a duplicidade de mensagens e o erro de CSS. A disciplina do teste é o que separa a codificação artesanal da engenharia de software.

8. Conclusão: Do Plano de Ação à Resolução Definitiva

Para encerrar o ciclo MASP e garantir o bloqueio definitivo do bug, estruturamos o seguinte Plano de Ação (5W2H):


Diretriz

Descrição da Ação

What (O quê)

Corrigir CSS da SideBar, implementar .distinct() no Django e sincronizar badges.

Why (Por quê)

Garantir paridade Desktop/Mobile e eliminar redundância de dados.

Where (Onde)

No SideBar.jsx (Frontend) e na View de Mensagens (Backend).

When (Quando)

Ciclo imediato de sprint em ambiente de desenvolvimento.

Who (Quem)

Desenvolvedor Full-Stack sob supervisão de QA.

How (Como)

Inserção de overflowY: 'auto' e revisão de filtros no Django ORM.

How Much (Custo)

Horas técnicas de desenvolvimento e homologação cruzada.



Protocolo de Controle:

  • Execução:  Injetar mensagem, ler no mobile e verificar se o badge decrementa e a opção "Sair" permanece acessível via scroll.

  • Controle (Resultado Esperado):  O comportamento real deve ser idêntico ao esperado (Zero duplicatas, badge sincronizado e menu completo).Utilizar uma metodologia estruturada como o MASP transforma o caos de um bug em um processo de aprendizado institucional. Reflita: você está realmente resolvendo as causas raízes dos seus problemas ou está apenas "apagando incêndios" na interface até o próximo deploy?



Resumo em vídeo e áudio







Nenhum comentário:

Postar um comentário

Entendendo a Metáfora "Home Office é Moto Boy"

Exemplo 4 de uso do MASP com IA em TI - O Mistério do Botão "Sair" - Lições de um mergulho profundo no método MASP

  O exemplo 4 de uso do MASP (Método de Análise e Solução de Problemas), com IA (Inteligência Artificial) em TI (Tecnologia da Informação), ...