O exemplo 3 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 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, na Beta v2.28m
1.1.1 Descrição do bug: No celular, não se consegue chegar ao “Sair”, no menu à esquerda.
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, na Beta v.2.28l.
[Who?] Quem está envolvido?
Quem está envolvido é o usuário responsável pela homologaçã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 celular, no componente SideBar.jsx.
[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.
[How?] Como surgiu?
Surgiu após o login no celular. No Desktop, onde o menu é horizontal, emitido pelo componente Header.jsx, não houve problema.
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 (Ocorre em homologação e não 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 adicionada uma nova opção, Mensagens, de forma incompleta).
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 no menu horizontal e no menu vertical, mas testado apenas no Desktop do desenvolvedor, que mostra o menu horizontal, antes de publicar para homologação).
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)
Conectividade: Instabilidade na rede afetou a troca de pacotes? NÃO SEI
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” foi adicionada e o comportamento implementado de forma incompleta.
Por quê? Porque no componente Header.jsx (menu horizontal, no Desktop) o comportamento ao clicar em “Mensagens” foi testado e no componente SideBar.jsx (menu vertical, no celular) não foi testado.
Por quê? Porque durante os testes no Desktop houve vários erros e o foco foi direcionado, totalmente, para o comportamento no Header.jsx.
Por quê? Porque quando os testes passaram no Desktop, os testes foram considerados concluídos e a versão Beta v.2.28i foi publicada para homologação.
Por quê? Porque o desenvolvedor esqueceu que faltavam os testes no celular. Resumindo, o comportamento ao clicar na opção “Mensagens” deve sinalizar a quantidade de mensagens não lidas com um ícone de círculo vermelho, contendo a quantidade de mensagens não lidas no centro do círculo. Este comportamento foi implementado no componente Header.jsx mas não foi implementado no SideBar.jsx, por esquecimento. No SideBar.jsx foi apenas adicionada a opção Mensagens, sem o ícone de formato circular, que contém a quantidade de mensagens não lidas. Portanto, houve falha na escrita do código, na revisão e nos testes.
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
5Comando
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.
Resultado do Prompt estruturado com MASP
Aqui está a continuidade da sua análise MASP, avançando para a elaboração do Plano de Ação, seguido do código corrigido.
Como estamos garantindo a compatibilidade estrita com o React 15.6.1, mantivemos a estrutura de componentes de classe (Class Components) e removemos tentativas de importação de hooks (como o useLocation que constava no SideBar.jsx original mas não era suportado ou utilizado nesta versão).
Etapa 4: Plano de Ação (5W2H)
Correção de Código: SideBar.jsx
Abaixo está o código atualizado do SideBar.jsx. As lógicas de evento global (window.addEventListener('messageRead', ...)), requisição Ajax e a estrutura do badge vermelho foram replicadas exatamente como no Header.
JavaScript
import React from 'react';
import { Link } from 'react-router';
import ajax from '../../ajax-utils'; // Adicionado import do ajax
import { logout, getLogedUser, isLoggedIn, getAccessToken } from '../../utils/AuthService'; // Adicionado getAccessToken ausente
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 // Estado inicial para o badge
};
this._handleLogout = this._handleLogout.bind(this);
this.showFaleConoscoModal = this.showFaleConoscoModal.bind(this);
this._handleFaleConoscoSubmit = this._handleFaleConoscoSubmit.bind(this);
this._updateUnreadCount = this._updateUnreadCount.bind(this); // Bind do novo método
}
componentDidMount() {
const { pathname } = window.location;
if (pathname != '/signup-profile'){
this.setState({user: getLogedUser()}, () => {
this._updateUnreadCount(); // Busca inicial de mensagens não lidas
});
}
if (pathname == '/signup-profile'){
this.setState({signup_profile: true});
}
// Ouvinte global: atualiza o sidebar quando a mensagem for lida
window.addEventListener('messageRead', this._updateUnreadCount);
}
componentWillUnmount() {
// Boa prática: limpar o listener ao desmontar para evitar vazamento de memória
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});
// getAccessToken agora está corretamente importado
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">
<ul className="side-nav fixed clearfix left" id="nav-mobile">
<li>
{ (isLoggedIn() ) && this.state.user && this.state.signup_profile == false ? (
<ul className="collapsible" data-collapsible="accordion">
<li>
<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;
O Mistério do Botão "Sair": 4 Lições Cruciais sobre Consistência em Apps Mobile
1. Introdução: O Hook do Usuário "Preso"
Imagine a frustração de um usuário da versão Beta v2.28m do app VoteNet. Após concluir suas interações, ele clica no hamburger button para encerrar a sessão, mas encontra-se em um beco sem saída digital: a opção "Sair" simplesmente não aparece. O usuário está, efetivamente, "preso".Este cenário, identificado em fase de homologação, não é um mero deslize estético. Como especialista, vejo aqui uma falha crítica de lógica e processo. O botão de logout, posicionado estrategicamente ao final da lista vertical do SideBar.jsx, tornou-se inacessível porque um erro de renderização anterior interrompeu o processamento do componente. O que parece um "bug visual" é, na verdade, um sintoma de um sistema quebrado por falta de rigor técnico.
2. A Armadilha do Teste "Desktop-First"
A investigação técnica revelou uma assimetria perigosa: a nova funcionalidade de "Mensagens" funcionava perfeitamente no Header.jsx (utilizado no Desktop), mas "quebrou" o SideBar.jsx (Mobile). Ao aplicar o Diagrama de Ishikawa, o pilar de Mão de Obra tornou-se o culpado evidente. O desenvolvedor, focado em resolver os desafios da interface horizontal, negligenciou a paridade com a versão mobile."O desenvolvedor esqueceu que faltavam os testes no celular... o foco foi direcionado, totalmente, para o comportamento no Header.jsx."Testar apenas em uma resolução é um risco crítico. No VoteNet, a entrega foi considerada concluída assim que os erros do Desktop foram sanados, ignorando que o código mobile, embora compartilhe a lógica de negócio, reside em arquivos distintos que exigem validação individual e específica.
3. Simetria é Mais que Estética: O Caso do Badge de Mensagens
A falha técnica central reside na ausência de sincronia entre os componentes. Enquanto o Desktop exibia o badge de notificações (o círculo vermelho), o mobile apresentava uma tag de link estática e incompleta. A ausência de variáveis cruciais e a falta de importação de utilitários como o ajax e o getAccessToken no SideBar.jsx causaram um erro de referência.Como o botão "Sair" é o último item da lista, a falha na lógica de renderização do item "Mensagens" (posicionado acima) impediu que o React terminasse de "desenhar" o restante do menu. Para o usuário, a experiência é fragmentada; para a engenharia, é um erro de integridade. A correção exige a implementação do estado unreadCount e a configuração de um ouvinte global (window.addEventListener('messageRead', ...)) no método componentDidMount, garantindo que o estado de mensagens não lidas seja consistente em qualquer lugar que o usuário acesse.
4. MASP e 5W2H: A Ciência por Trás da Correção
Tratar um bug de forma profissional exige fugir da "tentativa e erro". Utilizamos o MASP (Método de Análise e Solução de Problemas) para encontrar a causa raiz, desdobrando-a em um plano de ação 5W2H rigoroso para o SideBar.jsx:
O que (What): Sincronizar a opção "Mensagens" no mobile com a lógica do desktop e corrigir importações ausentes.
Por que (Why): Padronizar a UI/UX e evitar que falhas de renderização bloqueiem o acesso à opção "Sair".
Quem (Who): Desenvolvedor Frontend.
Como (How): Importar os módulos ajax e getAccessToken, inicializar o estado unreadCount: 0, implementar o método _updateUnreadCount e configurar o listener global no ciclo de vida do componente.
Quanto custa (How Much): Aproximadamente 1 hora de desenvolvimento mais testes focados em dispositivos móveis.Este rigor garante que a causa raiz — a falta de variáveis no escopo — seja eliminada, permitindo que a lista vertical seja renderizada até o fim.
5. O Desafio do Código Legado (React 15.6.1)
A análise da Máquina (infraestrutura) revelou um detalhe vital: o bug era invisível em ambiente de Desenvolvimento, mas manifestou-se em Homologação. Em sistemas legados operando com React 15.6.1 e Node 6.17.1 , a manutenção exige precisão cirúrgica.Neste ambiente, não temos o luxo de usar Hooks modernos como useLocation ou useEffect. A correção precisou ser feita via Class Components , utilizando métodos de ciclo de vida tradicionais. Manter a compatibilidade estrita é fundamental; tentar forçar padrões modernos em uma estrutura antiga sem o devido suporte de bibliotecas poderia introduzir efeitos colaterais ainda mais graves na estabilidade do sistema.
6. Conclusão: O Próximo Passo para a Homologação
A correção definitiva do "mistério do botão sair" não termina com o ajuste do código. Ela estabelece uma nova diretriz: a homologação deve ser tão rigorosa quanto o desenvolvimento. O processo de code review agora deve validar obrigatoriamente se as alterações no Header.jsx foram espelhadas no SideBar.jsx.A qualidade de um app é definida pela sua consistência em todos os pontos de contato. Se uma informação (como um badge de mensagens) existe em uma plataforma, ela deve ser uma verdade universal em todo o ecossistema do software.Fica a provocação: em seus últimos commits , você garantiu que a sua correção "Desktop" não deixou seus usuários "Mobile" sem uma rota de saída?

Nenhum comentário:
Postar um comentário