Argumentos e resultados

Após retornar do API Days em Londres, estou estudando padrões de design para APIs. O último artigo que li foi “Arguments and Results” de James Noble (1), publicado em 1997 e ainda extremamente relevante. Parte do meu trabalho atual, desenvolver um data warehouse, é otimizar o transporte de grandes volumes de dados. E se eu quiser usar APIs, como posso fazer isso de forma eficiente? Há um consenso de que APIs REST não são adequadas em cenários de alto volume e estudando esse tópico cheguei ao Noble.

O artigo discute padrões para protocolos de objetos e para isso existem dois grupos:

  • Como enviar objetos (Argumentos): Arguments object, Selector object and Curried object
  • Como receber objetos (Resultadoss): Result object, Future object and Lazy object

Padrões

  • Arguments object: Este padrão é utilizado para agilizar a assinatura de um método, consolidando argumentos e objetos comuns e modificando a assinatura do método para aceitar esse objeto consolidado. Traz diversas vantagens, você deixa seu domínio explícito; seus clientes podem utilizar o que têm em mãos (os objetos, em vez de valores separados); e você é capaz de separar a lógica de processamento da sua lógica de negócios

De

    void Send-FixedIncome(EntityName, IssueDate, MaturityDate, PrincipalAmount, ...) { }

Para

    void Send-FixedIncome(FixedIncome) { }

“adding an eleventh argument to a message with ten arguments is qualitatively quite different to adding a second argument to a unary message”

  • Selector object: Quando você possui métodos com argumentos bastante semelhantes, este padrão introduz um seletor que permite escolher um deles. Noble mencionou que você poderia um enum, talvez usar GoF a Flyweight resolveria.

De

    void CalculateHomeLoanAmount(HomeLoan, Collateral) { }
    void CalculateHomeLoanAmount(HomeLoan) { }
    void CalculateAutoLoanAmount(AutoLoan) { }
    void CalculatePersonalLoanAmount(PersonalLoan) { }

Para

    void CalculateAmount(LoanType, Loan) { } //Loan would be the interface for all loan types

“Protocols (APIs) where many messages perform similar functions are often difficult to learn and to use, especially as the similarity is often not obvious from the protocol’s documentation”

  • Curried object: do mundo da programação funcional, o currying quebra uma função com vários argumentos em funções menores, onde cada uma dessas funções recebe alguns (geralmente um) dos argumentos originais; essas funções são chamadas em sequência então. Noble introduz esse padrão para um cenário onde o chamador não precisa fornecer todos os argumentos (por exemplo, constantes), o método pode fornecer em seu nome. Nos termos do GoF, ele atua como um proxy.

De

    void SettleDebt(Loan, ParcelsToPay) { } # no. of parcels can be retrieved from the loan 

Para

    int GetOpenParcels(Loan) { }
    void SettleDebt(Loan) { () => Settle(Loan) } # in Settle no. of parcels is retrieved

“These kinds of arguments increase the complexity of a protocol. The protocol will be difficult to learn, as programmers must work out which arguments must be changed, and which must remain constant.”

  • Results object: Para cenários complexos, podem ser necessárias várias chamadas de método para gerar o resultado esperado. Seu objeto de resultados deve ser único com tudo nele. Este padrão pode ser visto como o outro lado do padrão Curried Object. Um aspecto que vale a pena mencionar é quando essas diversas chamadas significam vários sistemas. Nesse caso. um objeto de resultado ajuda a reduzir o acoplamento e atua como uma abstração em torno deles.

“Perhaps the computation returns more than on object”

  • Future object: Este padrão é empregado quando precisamos executar uma operação demorada e realizar outras tarefas enquanto aguardamos a conclusão da operação. Em essência, nosso objetivo é processar um resultado de forma assíncrona e provavelmente invocar um retorno de chamada após a conclusão.

” Sometimes you need to ask a question, then do something else while waiting for the answer to arrive”

  • Lazy object: Às vezes você precisa fornecer um resultado, embora não haja 100% de certeza se o método será chamado. A vantagem disso é que não obtemos dados desnecessariamente.

“Some computations can best be performed immediately but the computation’s result may never be needed”

Em suma, estes conceitos já são bastante difundidos. Qualquer linguagem de programação mainstream tem suporte para métodos assíncronos (Lazy object) e avaliação lenta (Lazy object). Além disso, um bom design OO faz com que o ‘Arguments object’ e o ‘Selector object’ apareçam naturalmente. Foi um bom artigo back-to-basics para me lembrar da importância de um bom design em meus métodos de API.

CSS mais fácil

Damien Riehl é um advogado especializado em tecnologia e também um músico. E ele não concorda como os processos de violação de direitos autorais, para ele música pode ser vista como matemática. E se você lembrar que há apenas 8 notas musicais, Damien teve a brilhante ideia de fazer um algoritmo que fizesse todas as combinações e colocou no domínio público. Segundo ele, isto pode ajudar naqueles casos em que alguém é processado apenas porque usou uma combinação usada por outro, e a segunda pessoa nem sabia. Veja o faq em http://allthemusic.info/ para entender melhor.

Não sou um advogado, nem estou defendendo a pirataria, o que me chamou a atenção foi a sacada de notar que há um espaço finito de possibilidades. Acho que há um fascinio em poder dizer ‘aqui está tudo sobre o tema X’, pessoalmente foi o que me atraiu no mestrado. Não vou ser arrogante de dizer que sei tudo sobre Design Thinking mas eu abordei meus estudos com este objetivo. E agora sei uma ou duas coisas a respeito …

Outro tema: Pense no design de uma página HTML ou SPA, quantos modos diferentes há de fazê-la? Usamos CSS para controlar o que será exibido. As cores são finitas, vão de #000000 até #FFFFFF; as bordas são top-bottom-left-right; e por aí vai. Adam Wathan notou isto e desenvolveu o TailwindCSS. Com o TailWind, você escreve seu CSS sem sair da sua pagina HTML. Veja a diferença, antes, se eu queria que meu texto fosse azul e negrito, eu faria isto:

style.css

 .info{
        color: blue;
        font-weight: bold;
    }

index.html

<p class="info">
    Lorem Ipsum
</p>

E voilà, texto azul e negrito. O TailWindCSS permite que você escreva diretamente e ele tem uma biblioteca com centenas e centenas de possibilidades. Assim que você usa no seu html ele gera o CSS automaticamente. Este é um detalhe, uma aplicativo roda no seu terminal e varre as suas páginas para saber o que gerar:

index.html

<p class="text-blue font-bold">
    Lorem Ipsum
</p>

ou texto bem grande, negrito, sublinhado, azul-celeste e centralizado na página:

<p class="text-3xl font-bold underline text-sky-400 text-center">
    Lorem Ipsum
</p>

UnoCSS leva a ideia adiante e elimina completamente o arquivo css. No UnoCSS há um script que analisa as suas páginas em runtime e gera as classes para você. E nāo é necessário um aplicativo rodando em background. Mágico! Note que o modo de escrever é exatamente igual ao TailWindCSS.

index.html

<p class="text-blue font-bold">
    Lorem Ipsum
</p>

Tenho usado muito UnoCSS. Mas tenho minhas críticas, o grande número de classes pode tornar o código HTML verboso, e é um fato, seu HTML fica difícil de entender. E o CSS gerado pelo TailWindCSS é legível apenas pelos desenvolvedores do … TailWind 😀.

Além disso, a dependência do framework em classes utilitárias pode levar a uma falta de consistência no design em todo o site, já que diferentes desenvolvedores podem usar classes diferentes para alcançar efeitos semelhantes. E uma vez que não há um arquivo CSS mantido pelo time, a necessidade de documentar as escolhas de estilo é essential.

Ainda assim, a praticidade parece para mim mostrar que frameworks assim serão cada vez mais populares.