artigo
anti-padrões: os erros que (quase) todo mundo comete no ServiceNow
God Business Rule, sys_id hardcoded, table proliferation e credencial em texto claro: cinco jeitos clássicos de sabotar a instância — e como sair.
Tem um tipo de erro que não aparece em nenhum curso introdutório. Ninguém ensina "como criar um God Business Rule" — ele nasce sozinho, uma linha de cada vez, sempre com uma justificativa razoável no momento. É sexta-feira, o prazo é segunda, e adicionar mais uma responsabilidade naquele Business Rule que já está aberto é mais rápido do que criar um Script Include novo. Seis meses depois, ninguém mais sabe o que aquele script faz inteiro, só pedaços dele.
Não é uma lista para apontar dedo. É uma lista de reconhecimento — os cinco anti-padrões mais comuns em instâncias ServiceNow, o porquê de cada um parecer uma boa ideia na hora, e o caminho de volta.
1. god Business Rule
O sintoma é sempre o mesmo: um Business Rule de 200 linhas que valida dados, calcula prioridade, atualiza registros relacionados, dispara notificação e ainda chama uma API externa. Tudo num script só, porque o current e o previous já estavam ali, disponíveis, tentadores.
O problema não é o tamanho por si só — é que um script assim não tem como ser testado em partes (como você isola só a validação?), não tem como ser debugado com confiança (qual das 200 linhas jogou o erro?) e não tem como ser reaproveitado por outro processo. Se outro Business Rule também precisa calcular a prioridade, a opção vira copiar e colar, e agora você tem duas fontes de verdade para manter sincronizadas.
O antídoto já apareceu por aqui quando falei de Business Rules: Script Include para a lógica, Business Rule como orquestrador magro chamando os métodos. Uma régua prática, e é régua minha, não regra da plataforma — se o BR passou de umas poucas dezenas de linhas efetivas (sem contar comentários e chaves soltas), provavelmente ele está fazendo trabalho que não é dele.
2. sys_id hardcoded
Você está em DEV, precisa apontar um registro para um grupo específico, copia o sys_id da URL e cola no script:
// funciona em DEV, quebra em QA e PROD silenciosamente
var groupId = '8a5055c9c61122780192b5fc05bc0001';
current.setValue('assignment_group', groupId);Funciona. Passa no teste. O Update Set sobe para QA — e lá esse sys_id não existe, porque o grupo em QA foi criado numa instância diferente, em outro momento, com outro sys_id. O campo fica vazio ou aponta para um registro aleatório, e ninguém percebe até um chamado sumir na fila errada.
A saída é nunca depender de um identificador que muda entre instâncias. Três formas de resolver, em ordem de preferência:
// query por campo estável — name é igual em toda instância
var grp = new GlideRecord('sys_user_group');
grp.addQuery('name', 'ITSM Level 1 Support');
grp.setLimit(1);
grp.query();
if (grp.next()) current.setValue('assignment_group', grp.getUniqueValue());
// ou: System Property configurável por ambiente
var groupId = gs.getProperty('x_acme_itsm.routing.l1_group_id');
if (groupId) current.setValue('assignment_group', groupId);Query por campo estável para casos simples, System Property quando o valor muda por ambiente, tabela de configuração customizada quando existem vários mapeamentos (categoria → grupo, por exemplo). O denominador comum: zero literais de sys_id no código.
3. table proliferation
"Preciso de campos específicos, vou criar u_my_request do lado de sc_request." Parece inofensivo — é só uma tabela nova. O problema é tudo que fica para trás: workflow de aprovação nativo, SLA já configurado, relatórios e dashboards padrão, integração com o catálogo de serviços, compatibilidade com portal. Tudo isso você vai reescrever do zero, e depois manter para sempre, inclusive a cada upgrade de versão.
4. credencial hardcoded
Essa é a mais grave das cinco, porque o raio de exposição é maior do que parece. Uma API key escrita direto no script não fica só ali: ela é gravada em texto claro no histórico de versões do artefato, fica visível para qualquer pessoa com acesso de leitura à tabela de scripts, é exportada como XML legível dentro do Update Set, e se esse Update Set for parar num repositório Git por engano — o que acontece com mais frequência do que se gostaria — a credencial está exposta para quem tiver acesso ao repo, para sempre, porque histórico de Git não esquece.
A forma correta é Connection & Credential Alias: a Connection define endpoint, porta e protocolo; a Credential guarda o segredo, criptografado pela plataforma; o script acessa via sn_cc.ConnectionInfoProvider e nunca toca o valor bruto. Rotacionar a credencial vira uma edição de registro, sem tocar em uma linha de código — o mesmo padrão que já apareceu em arquitetura de integração para autenticação com sistemas externos.
5. editar o artefato out-of-box direto
Business Rule OOB não faz exatamente o que você precisa, então você abre, edita, salva. Funciona hoje. O problema chega no próximo upgrade: a plataforma detecta que o artefato foi modificado, pula a atualização para não sobrescrever o seu trabalho e registra aquilo como skipped change. Alguém vai ter que abrir o Upgrade Center e decidir, item por item, entre reverter para a versão base, mesclar ou manter a customização — comparando as duas versões linha por linha. Em instâncias com dezenas de artefatos OOB alterados direto, isso vira dias de trabalho a cada ciclo de upgrade.
| Em vez de editar o OOB... | faça isso |
|---|---|
| Business Rule | crie um BR novo na mesma tabela, com Order maior ou menor que o original |
| Script Include | crie uma classe que estenda a OOB (Object.extendsObject()) e sobrescreva só o que precisa |
| Widget de portal | clone o widget pelo botão Clone Widget no cabeçalho do registro, com nome e prefixo da sua app |
| UI Policy | desative a OOB e crie uma nova com a condição desejada |
o checklist que fecha a porta
Nenhum dos cinco anti-padrões acima é exótico — todos passam despercebidos num code review apressado. Um checklist simples antes de fechar Update Set ou aprovar PR pega a maioria:
Nenhum item da lista é sofisticado. A função do checklist não é ensinar algo novo — é garantir que a decisão de atalho, quando ela acontecer, seja consciente e não acidental.
e agora?
- Se você reconheceu algum desses cinco no seu próprio código, o próximo passo não é reescrever tudo hoje à tarde — é catalogar onde estão antes que o próximo upgrade force a conversa.
- Revise as ACLs e roles envolvidas nos artefatos que você for tocar: ACL e roles: a porta e a fechadura ajuda a não trocar um anti-padrão por uma brecha de segurança.
- Se
table proliferationfor o seu caso, vale revisitar modelo de dados: tabelas, campos e relacionamentos antes de decidir entre estender e criar do zero.