Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

211
Visualizações
SOLID - Dependency Inversion Principle: Should utility/helper functions be an interface or can I use its concrete implementation?

Given this dummy code, which has an if statement with a verbose code (imagine this is a really verbose if statement), I decide to create a util function to make my code cleaner. When I choose to create a util function, should it be implemented as an interface or can I implement the concrete function instead? I may use this same function again in other class.

Dummy code:

export class UserRepository {
      constructor (private readonly database: DatabaseProtocol) {}
    
      async findUserByEmail (data: Record<string, any>): Promise<IUser | null> {
        const userCollection = this.database.collection('users')
    
        if (Object.keys(data).length === 0) return null
    
        const user = await userCollection.findOne({ email: data.email })
    
        return user
      }
    }

Concrete implementation:

 export class UserRepository {
      constructor (private readonly database: DatabaseProtocol) {}
    
      async findUserByEmail (data: Record<string, any>): Promise<IUser | null> {
        const userCollection = this.database.collection('users')
    
        if (isEmpty(data)) return null
    
        const user = await userCollection.findOne({ email: data.email })
    
        return user
      }
    }

Interface implementation:

export class UserRepository {
  constructor (
    private readonly database: DatabaseProtocol,
    private readonly isEmpty: IsEmptyProtocol
  ) {}

  async findUserByEmail (data: Record<string, any>): Promise<IUser | null> {
    const userCollection = this.database.collection('users')

    if (this.isEmpty(data)) return null

    const user = await userCollection.findOne({ email: data.email })

    return user
  }
}

Private method:

export class UserRepository {
  constructor (
    private readonly database: DatabaseProtocol
  ) {}

  async findUserByEmail (data: Record<string, any>): Promise<IUser | null> {
    const userCollection = this.database.collection('users')

    if (this.isEmpty(data)) return null

    const user = await userCollection.findOne({ email: data.email })

    return user
  }

  isEmpty (data: Record<string, any>): boolean {
    return Object.keys(data).length === 0
  }
}

Which option above would be considered the best practice?

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

There's not really any alternatives implementation you'd want to inject for such helper functions, therefore an interface would be overkill and combersome to use.

If you look at java, they usually have such utility functions in plural classes like Arrays where we can find utilities such as Arrays#asList. JavaScript does the same with for instance Object.entries.

With modules you could just have an objects.ts module and export an isEmpty function to reuse.

One thing to be careful about though is whether "empty" could have different meanings. For instance, perhaps "empty" in another context could mean there could be keys, but they don't count if they reference null or undefined. Therefore, it's important to document the behavior properly.

Furthermore, the empty check is really domain-specific. It seems to represent in your case whether or not there's an email filter present. Therefore, rather than calling isEmpty directly you'd most likely have a private hasEmailCriteria function or something.

However, in the end I also think the signature of findUserByEmail is pretty bad. Why not just accept an email such as findUserByEmail(email: string) instead? Or even better, perhaps findUserByEmail(address: EmailAddress).

about 4 years ago · Juan Pablo Isaza Relatório

0

Here are my 2 cents:

  1. If the IsEmpty functionality is needed only for UserRepository class then make it a private method of that class.
  2. If the IsEmpty functionality is needed by some (by not all) classed in your program, then go with the Interface implementation: solution you proposed in your question.
  3. If the IsEmpty functionality is used in all your classes (or in the vast majority), then make it a global class with static methods. I know, I know, Uncle Bob does not allow global state (and rightfully so), but this is an exception. This case is a cross-cutting concern (please see my answer here from more details).
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda