DEV Community

Cover image for 7 Lições aprendidas ao desenvolver bibliotecas
Alexandre Antonio Juca
Alexandre Antonio Juca

Posted on • Updated on

7 Lições aprendidas ao desenvolver bibliotecas

Criar uma biblioteca open source é uma experiência prazerosa para muitos desenvolvedores. Pois, permite criar uma solução para um determinado problema que outros desenvolvedores têm ou que irão ter e poupar tempo e esforço. E há uma possibilidade que centenas ou milhares de pessoas ao redor do mundo usem a solução.

É bem provável que já teve a oportunidade de usar muitas bibliotecas na sua carreira profissional mas será que já teve a oportunidade de criar uma biblioteca, gem, package etc? Quais são as coisas que um desenvolvedor pode fazer para criar uma biblioteca de boa qualidade e de fácil consumo? Como pode ajudar os consumidores da sua biblioteca a saber o que deu errado para corrigir? Quais são alguns princípios ou modelos mentais que possam ajudar você a criar algo que seja simples de usar? Como reduzir e lidar com a complexidade? Como lidar com mudanças que irão acontecer durante o ciclo de vida da sua biblioteca?
Nesta série de artigos irei responder essas perguntas e dar dicas para ajudar você a criar bibliotecas com maior qualidade, flexibilidade e que sejam mais fáceis de consumir. Mas antes há uma pergunta importante que todos nós devemos fazer.

1. Preciso mesmo de criar uma biblioteca?

Antes de investir tempo e energia para criar uma biblioteca, pesquise para ver se já existem outros disponíveis para resolver o seu problema. Ian Summerville ao falar sobre fundamentos de engenharia de software no seu livro intitulado Engenharia de software 9a edição expressou um conselho digno da sua atenção:

“Você deve fazer o melhor uso possível dos recursos existentes. Isso significa que, quando apropriado, você deve usar o software já desenvolvido, em vez de escrever um novo. — Ian Summerville”

Caso as bibliotecas existentes não sejam aptas para uso no seu projecto por razões de negócio, licenças, ou má qualidade, poderá seguir em frente. O tema a seguir mudou completamente a minha visão sobre desenvolvimento de software.

2. Pense no cliente

É essencial pensar no cliente final que irá consumir a sua biblioteca, neste caso o desenvolvedor. Isso envolve ter ou mostrar empatia, mas antes precisamos definir claramente o que significa ter empatia e depois veremos como isso está relacionado ao desenvolvimento e engenharia de software. De acordo com o site www.significados.com.br empatia significa:

“A capacidade psicológica para sentir o que sentiria uma outra pessoa caso estivesse na mesma situação vivenciada por ela. Consiste em tentar compreender sentimentos e emoções, procurando experimentar de forma objetiva e racional o que sente outro indivíduo.”

Daí poderá surgir uma pergunta da sua parte: Mas como isso está relacionado ao desenvolvimento de software?

Visto que a empatia permite nos colocar no lugar de uma outra pessoa, seguir os princípios de desenvolvimento orientado a empatia permite criar software centrado ao desenvolvedor, no caso que estejamos a desenvolver uma biblioteca. Vai ajudar-nos a pensar nas dificuldades do consumidor e diminuir fricção com uma documentação clara e fácil de entender. Também, se aplicado corretamente permite-nos criar software que seja mais fácil de usar e com uma interface ou API mais simples e um produto final de maior qualidade.

Como fazer na prática?

Pense em como o consumidor vai usar a sua biblioteca e veja o que pode complicar o trabalho dele e diminuir a sua produtividade. Vamos usar como exemplo uma biblioteca desenvolvido na NEXT para interagir com a API da ProxyPay para efectuar pagamentos na rede multicaixa e outra exemplo fictício.
A API poderia ser desenhado deste jeito:

Exemplo A1

val proxyPay = ProxyPayPayment()
proxyPay.config = ProxyPayConfig.getInstance()
proxyPay.referenceRequest = request
...

Antes de continuar a sua leitura, análise o código acima e procura problemas que um desenvolvedor pode encontrar.
Exemplo B1:


private void makeNormal(Customer customer) {
        Order o1 = new Order();
        customer.addOrder(o1);
        OrderLine line1 = new OrderLine(6, Product.find("TAL"));
        o1.addLine(line1);
        OrderLine line2 = new OrderLine(5, Product.find("HPK"));
        o1.addLine(line2);
        OrderLine line3 = new OrderLine(3, Product.find("LGV"));
        o1.addLine(line3);
        line2.setSkippable(true);
        o1.setRush(true);
    }

Em essência, criamos os vários objetos e os unimos. Se não podemos configurar tudo no construtor, precisamos criar variáveis temporárias para nos ajudar a construir o produto final — este é particularmente o caso em que você está adicionando itens nas coleções.

Este é a forma mais convencional que tenho visto para juntar um conjunto de objectos. Conseguiu notar como pode ser muito trabalhoso para o desenvolvedor montar todos os objectos necessários para sua tarefa?
Aplicando o princípio de empatia permite-nos achar uma maneira mais simples de lidar com o mesmo caso. Uma boa alternativa é usar um fluent interface e o Builder pattern.

Solução para A1:

val proxyPay = ProxyPayPayment.Builder()
        .addProxyPayConfiguration(ProxyPayConfig.getInstance())
        .addReferenceRequest(request)
        .build()  

Solução para B1:

private void makeFluent(Customer customer) {
        customer.newOrder()
                .with(6, "TAL")
                .with(5, "HPK").skippable()
                .with(3, "LGV")
                .priorityRush();
    }

Qual dessas opções deixa a intenção do código mais claro? É bem provável que a sua resposta seja os dois últimos e com boa razão visto que a API foi desenhada para ser legível e para fluir como um poema bem escrito. O preço de fazer isso é tirar mais tempo para pensar e construir a API mas com certeza o artefacto final será algo bem mais fácil para o cliente entender e consumir.

Em resumo

  1. Antes de começar a escrever uma única linha de código procura entender melhor o problema e colocar-se no lugar do cliente.

  2. Desenhar como os vários componentes da biblioteca irão interagir.

  3. Outro ponto essencial é desenhar a API e pensar em como o desenvolvedor vai usar a sua biblioteca e prever os possíveis problemas que possa encontrar ao usar a sua biblioteca.

3. Assume sempre que o cliente seja “estúpido”

Alt Text

Recentemente comprei uma cadeira para o meu escritório e tive o prazer de montá-lo. Todas as peças foram cuidadosamente colocadas e organizadas na sua caixa. O manual teve desenhos bem simples para ajudar-me a montar a cadeira sem ter que ligar um amigo (Quem quer ser milionário). O manual não tinha texto nenhum. Apenas números para apresentar os passos diferentes para montar a cadeira com sucesso. O que o fabricante da cadeira pensou antes de criar-lo? A equipe provavelmente pensou em como poderiam facilitar a vida de quem vai montar a cadeira e consequentemente poupar seu tempo. Eles assumiram que o cliente fosse “estúpido”. Quer dizer, diminuíram a complexidade para o benefício de quem vai montar.

Por vezes como desenvolvedores gostamos de mostrar o quão inteligente nós somos por criar coisas demasiados complexos ou usar recursos da linguagem de programação que são poucos conhecidas ou “exotéricos”. Isso cria uma barreira para quem vai usar a sua biblioteca. Porquê? Lembra que o desenvolvedor está com tempo limitado e precisa fazer uma entrega o mais rápido possível e na melhor qualidade possível. Isso pode causar vários problemas, um deles que merece maior destaque é:

O desenvolvedor pode cometer um erro ao usar a sua biblioteca se for demasiado complexo usá-o.

Do mesmo jeito que alguém pode cometer um erro ao montar uma cadeira porque há muitas peças e o jeito de montar-lá é demasiado complexo.

Como podemos reduzir complexidade?

O livro “The Laws of Simplicity” (As Leis da simplicidade) escrito por John Maeda diz algo que mudou o meu modo de pensar completamente e que é aplicável em quase tudo na vida incluindo desenvolvimento de software e tecnologia.

“A maneira mais simples de obter simplicidade
é através da redução ponderada.- John Maeda”

O segredo consiste em reduzir em vez de aumentar. Elimina tudo que não for necessário. Simplifique o seu código, a sua interface e aplique o padrão de desenho melhor adequado para o seu problema.

Qual vai ser o resultado disso?

A sua biblioteca será mais fácil de manter e consumir, e podes ter a certeza que os consumidores sentir-se-ão mais inteligentes por terem escolhido a sua solução.
No próximo artigo desta série irei abordar sobre outras dicas que irão ajudar você a criar bibliotecas melhores.

Alt Text

Este é o Alexandre Juca, ele é Engenheiro de Software na NEXT e é apaixonado por Fintechs, Segurança, I.A e Negócios.
A sua missão é revolucionar e impulsionar empresas usando tecnologia.

Lista de algumas bibliotecas open source desenvolvidas por Alexandre Juca e que tem ele como contribuidor:

ProxPay Elixir - https://github.com/nextbss/proxypay-elixir
ExOauth2 - https://github.com/AlexJuca/ex_oauth2
OktaAuth - https://github.com/nextbss/okta_auth
ProxyPay Kotlin — https://github.com/nextbss/proxypay-kotlin
BiometricKit — https://github.com/AlexJuca/BiometricKit
Kamba Android SDK — https://github.com/usekamba/kamba-android-sdk
Kamba Woocommerce — https://github.com/usekamba/kamba-woocommerce
Hades - https://github.com/fklement/hades

Discussion (0)