O que é uma interface em programação?

Willyan Guimarães
experienceCode
Published in
5 min readJan 24, 2023

Tentando explicar um conceito de programação em poucas linhas de código, ou pelo menos tentando.

Nas interfaces do espaço
Photo by NASA on Unsplash

Seja qual for a linguagem de programação o conceito de interface é quase onipresente na maioria delas. Mas tentando olhar de forma mais abstrata, o que realmente é uma interface ? Qual sua importância no design de software ? Existe alguma regra para definir boas interfaces ? Então, vamos lá!

Afinal, o que é uma interface ?

Existem várias definições do que é uma interface. Para algumas linguagens de programação, elas permitem:

Muitas vezes interfaces estão ligadas a conceitos de orientação a objetos como composição e herança.

Podemos ainda também enxergar interfaces como códigos pelos quais chamamos com base em regras pré-definidas como argumentos de entrada e dados de saída. Dessa forma poderíamos ampliar o escopo de entendimento do que é interface para métodos/funções/APIs.

Enfim, pense que interfaces definem o que é feito sem dizer como. É tudo (deve ser) em favor de abstração, facilidade de uso e inversão de dependência a fim de buscar baixo acoplamento. Para exemplificar, vamos pensar quando estamos usando uma estrutura de dados em uma linguagem de programação moderna, como Java, Kotlin, Python, Go, etc. Se você precisa criar uma lista, array ou um mapa, é apenas necessário interagir com as interfaces que possuem a implementação dessas estruturas. Você não precisa escrever do 0 uma lista, array, mapa.

Em termos do que constitui uma interface poderíamos dizer que ela é composta por dois elementos básicos: formais e informais.

Elementos formais nada mais são que as partes especificadas explicitamente no código, por exemplo, a assinatura de um método, que inclui o nomes e tipos de seus parâmetros, o tipo de seu valor de retorno e informações sobre exceções lançadas pelo método.

Elementos informais são recursos que não podem ser expressados pela linguagem de programação. São informações de alto nível em relação ao comportamento ou restrições. Um exemplo seria uma interface que para ser utilizada o desenvolvedor precisa conhecer uma ordem específica de chamada dos métodos (funções). Também consideramos aqui comentários no código e documentação mais abrangente.

Qual a importância da interface no design de software ?

Um bom design de software consiste em interfaces que são simples de se utilizar e entender. Existem duas vantagens em modelar interfaces com essas características.

Primeiro, uma interface simples minimiza complexidades e dependências entre classes/módulos/sistemas/APIs.

E por fim, quando uma interface é simples é bem provável que seja estável e que mesmo com mudanças internas na sua implementação ela não venha a sofrer alterações em seus pontos de entrada, o que minimiza a propagação de mudança de seus usuários.

Como definir (ou pelo menos tentar) escrever boas interfaces ?

Não existe uma resposta simples para uma pergunta tão desafiadora como essa. O que nos resta é tentar seguir o feijão com arroz de alguns princípios que podem nos orientar a escrever um bom código. Então vamos de sugestões.

Entenda quais abstrações podem ser criadas

Compreender as abstrações envolvidas em um determinado contexto ajudam muito a criar interfaces minimizando a complexidade. Essa é a ideia por trás da definição de abstração, que é a visão simplificada de uma entidade no qual omite detalhes não importantes.

Um exemplo:

class Funcionario {
BigDecimal salario(){
}
}

class Estagiario {
BigDecimal salario(){
}
}

class Gerente {
BigDecimal salario(){
}
}

Reflita: Qual tipo de abstração pode ser feita aqui ?

Poderíamos criar uma abstração utilizando uma interface para representar “Pessoas” no sistema:

interface Pessoa {
BigDecimal salario();
}


class Funcionario implements Pessoa {
@Override
BigDecimal salario(){
}
}

class Estagiario implements Pessoa {
@Override
BigDecimal salario(){
}
}

class Gerente implements Pessoa {
@Override
BigDecimal salario(){
}
}

Uma oportunidade que surge dessa construção é tirar proveito do polimorfismo. Em algum momento pode surgir no código a necessidade de buscar o salário e daí podemos simplesmente utilizar a própria interface.

class CalculadoraDeSalarios {

void pagarSalario(Pessoa pessoa) {
var valor = pessoa.salario(); //devolve o salário de qualquer subclass

}

}

Lembre-se: programe voltado a interface não a implementação.

Cuidado com dependências entre operações

Como já comentado, suponha que exista uma interface na qual diversas operações existem e você precisa chamar com alguma ordem para executar alguma ação, exemplo:

interface Transacao {

void validaSaldo(Conta conta);
void validaBloqueio(Conta conta);
void transfere(Conta origem, Conta destino);

}

Para realizar uma transferência entre contas é preciso realizar a validação de saldo e de bloqueio na conta origem dos valores. Existe uma forma simples de mitigar o risco de um mal entendimento nesse cenário explicando os passos a partir de uma boa documentação.

Porém, uma forma diferente de tratar essa solução seria incorporar as validações diretamente na implementação do método transfere(). Dessa forma, qualquer chamador não precisaria saber da dependência das verificações para chamar o método de transferência.

Cuidado com os elementos informais

Como já explicado, os elementos informais de uma interface podem ser mais implícitos de maneira que possa surgir alguma informação “oculta” sobre o uso de algum recurso.

É muito importante deixar evidente o comportamento, seja por comentários em código ou mesmo por documentação. Mas se algo está muito complicado pode ser sinal de que existem pontos de melhoria possíveis no design dessa interface.

De qualquer forma, lembre-se: quanto menos elementos informais existem menos complexa é uma interface.

O Princípio de Responsabilidade Única

O SRP (Princípio de Responsabilidade Única) nos ajuda muito a entender mais sobre coesão. Quanto mais coeso é a estrutura de uma interface menos chances de estar resolvendo o problema certo no lugar errado. Não é uma regra unânime mas se você já se deparou com uma interface de um determinado contexto com uma quantidade muito elevada de operações existe uma probabilidade que essa esteja resolvendo mais problemas do que deveria.

Conclusão

Interfaces representam os pontos de entrada de uma aplicação de software. Como desenvolvedor é muito importante buscar compreender a necessidade de buscar simplicidade no design desses componentes. Esses cuidados ajudam a mitigar os riscos provenientes de complexidade e acoplamento entre pequenas e grandes partes de código.

“Livros sobre arte não prometem lhe tornar um artista.”

Robert C. Martin

Este texto foi inspirado no quarto capítulo do livro “A Philosophy of Software Design”.

--

--