Skip to content

Instantly share code, notes, and snippets.

@rwillians
Last active February 11, 2024 15:31
Show Gist options
  • Save rwillians/472833a2df13f44c5fabbb12380c4491 to your computer and use it in GitHub Desktop.
Save rwillians/472833a2df13f44c5fabbb12380c4491 to your computer and use it in GitHub Desktop.
if, switch ou strategy

If

Se há apenas duas possibilidades, uso if/else apenas como ternário:

return foo === null
  ? fizz
  : buzz

Se multiples possibilidades E é preciso fazer um processo de eliminação (ex: eliminar os casos de erro), uso ifs com early return. Inclusive tratar os erros primeiro é algo recomendado em Object Calisthenics (pesquisar por "Object Calisthenics ~programming"). A ideia é tratar os erros o quanto antes para que a logica de sucesso esteja disposta da forma mais clara o possível. Não se trata de performance, mas sim, de legibilidade.

const res = await fetch(/* */)

if (res.status === 401) {
  throw new AuthenticationRequiredError(/* ... */)
}

if (res.status === 403) {
  throw new NotAuthorizedError(/* ... */)
}

if (res.status === 422) {
  throw new ValidationError(/* ... */)
}

if (res.status !== 200) {
  throw new SomethingWrongIsntRightError(/* ... */)
}

return { /* ... */ }

Switch

Raramente uso mas é útil quando se tem um campo discriminatório à partir do qual será feita uma "bifurcação" (branching) de código. É mais legível quando se há uma quantidade limitada e pequena de opções (tipo um Enum do TS). Considero mais adequado quando o statement para cada opção é curto (one-liner). Quando o statemente é maior do que isso ou quando há muitas opções, considere usar Strategies.

function validarDocumento(documento) {
  switch (documento.tipo) {
    case 'cpf': 
      return validarCpf(documento.numero)
    case 'passaporte':
      return validarPassaporte(documento.numero)
    case 'cnpj':
      return validarCnpj(documento.numero)
    default:
      throw new DocumentoNaoSuportado(/* ... */)
  }
}

Strategy

Quando um switch está se tornando insustentável por ter muitas opções (baixa legibilidade e/ou baixa clareza), dá pra fazer essa gamb do bem:

const VALIDADORES = {
  cpf: validarCpf,
  passaporte: validarPassaport,
  cnpj: validarCnpj
}

function validarDocumento(documento) {
  const validador = VALIDADORES[documento.tipo]

  if (validador === undefined) {
    throw new DocumentoNaoSuportado(/* ... */)
  }

  return validador(documento.numero)
}

No entanto, quando a quantidade de possibilidades é grande e/ou novas possibilidades continuam sendo adicionadas e/ou a condição é mais complexa do que apenas um campo discriminatório, provavelmente já é hora de partir para um padrão de design de Estratégias. Meu exemplo vai ser bem basicão, faz dá pra fazer mais "fancy" também (extrair cada estratégia em seu arquivo e se pá usar classes se esse for o tipo de droga que vc usa, etc).

// const cpf = require('./strategies/cpf.js')
// const passaporte = require('./strategies/passaporte.js')
// const cnpj = require('./strategies/cnpj.js')

const cpf = {
  matches: ({ tipo }) => tipo === 'cpf',
  validade: ({ número }) => /*  logica de validar aqui, ou chama a fn de validar cpf se vc precisar reutilizá-la */
}

const passaporte = {
  matches: ({ tipo }) => tipo === 'passaporte',
  validate: ({ numero }) => /* ... */
}

const cnpj = {
  matches: ({ tipo }) => tipo === 'cnpj',
  validate: ({ numero }) => /* ... */
}

// ordenado por prioridade e/ou documento mais provável pois
// a seleção da estratégia correta tem tempo-complexidade `O(n)`
// no pior caso.
const STRATEGIES = [
  cpf,
  passaporte,
  cnpj,
  // ...
]

function validarDocumento(documento) {
  const validador = VALIDADORES.find((validador) => validador.matches(documento))

  if (validador === undefined) {
    throw new DocumentoNaoSuportado(/* ... */)
  }

  return validador.validate(documento)
}

Conclusão

Segue seu coração, prefira legibilidade e clareza sempre que possível, e, na dúvida, consulte seu time para escolher qual opção fica melhor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment