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.

6 min de leitura servicenow anti-padrões arquitetura

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:

javascript
// 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:

javascript
// 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 Rulecrie um BR novo na mesma tabela, com Order maior ou menor que o original
Script Includecrie uma classe que estenda a OOB (Object.extendsObject()) e sobrescreva só o que precisa
Widget de portalclone o widget pelo botão Clone Widget no cabeçalho do registro, com nome e prefixo da sua app
UI Policydesative 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 proliferation for o seu caso, vale revisitar modelo de dados: tabelas, campos e relacionamentos antes de decidir entre estender e criar do zero.
LinkedIn X/Twitter WhatsApp ☕ me paga um café