Advent of Code

Eu adoro Dezembro. Natal, Ano-Novo, uma ou 2 semanas de ferias, a retrospectiva das conquistas do ano e … AdventOfCode. O AdventOfCode é um desafio anual de programação que consiste em quebra-cabeças que podem ser resolvidos em qualquer linguagem de programação. O evento é direcionado para pessoas com diferentes níveis de habilidade em programação e oferece uma oportunidade para aprimorarem nossas habilidades e aprender novas técnicas. Os desafios são lançados diariamente durante o mês de dezembro até o dia 25, no natal. Sempre há 2 problemas e para cada um resolvido você ganha uma estrela.

Vou ser honesto e dizer que até 2022 eu resolvia alguns desafios mas nunca fui consistente. Este ano eu decidi levar a sério e até o dia 8 eu coletei todas as 16 estrelas. E como disse acima, estou encarando como uma oportunidade de aprendizado: todo problema tem um exemplo com a solução, então cá estou fazendo TDD, o ciclo clássico red-green-refactor; todo dia você baixa um arquivo texto como input e resolve para cada uma das estrelas, então cá estou com um template automatizado em node que gera uma estrutura comum de arquivos e pastas; os problemas podem ser resolvidos de vários modos, então cá estou calculando o desempenho da minha solução e otimizando; estou publicando as minhas respostas dia-a-dia, então cá estou comentando o meu código para que minhas intenções sejam claras; como há um problema por dia, então cá estou encarando cada dia como uma versão, automatizei a geração de versões no Github usando release-please.

Minha estrategia cada dia tem sido a mais ingênua, tento resolver tudo por força-bruta. Quando demora muito, eu paro e penso em algo melhor. Se está aceitável (bem, aqui é bastante subjetivo, qualquer coisa rodando em menos de 3 minutos, ok), eu envio as respostas e ao fim do dia revisito o problema e reflito se há um modo melhor de fazer. Um exemplo, em um dia era necessario calcular caminhos usando um mapa com instruções. Minha primeira abordagem foi com um loop, depois de resolvido percebi que poderia usar o mínimo múltiplo comum dos diversos caminhos.

Vamos ver se consigo manter-me em dia com os problemas, tem sido muito divertido, eu recomendo fortemente!

OpenAI Dev Day

Preciso falar esta semana do keynote da OpenAI no evento para desenvolvedores (https://www.youtube.com/watch?v=U9mJuUkhUzk). Havia uma percepção que o ChatGPT estava em declínio, que as respostas não estavam tao boas. Neste tweet, Mike Young lista várias threads no Reddit com a mesma queixa (https://twitter.com/mikeyoung44/status/1672971689573990400); este paper (https://arxiv.org/pdf/2307.09009.pdf) quantifica a queda de precisão no algoritmo); e, nesta entrevista (https://olhardigital.com.br/2023/08/22/pro/chatgpt-ja-esta-em-declinio-afirma-neurocientista-da-unifesp/), o neurocientista Álvaro Dias também diz que o ChatGPT está piorando. Some-se a isto os processos em andamento por uso indevido (https://www.bbc.com/news/technology-66164228#:~:text=US%20comedian%20Sarah%20Silverman%20is,of%20the%20firms’%20AI%20systems.
, https://llmlitigation.com, https://www.ft.com/content/aec1679b-5a34-4dad-9fc9-f4d8cdd124b9, https://www.npr.org/2023/08/16/1194202562/new-york-times-considers-legal-action-against-openai-as-copyright-tensions-swirl). Nao parecia um bom momento mas as novas noticias do evento colocam o ChatGPT novamente nas manchetes.

Agora há a possibilidade de criar versões personalizadas do ChatGPT para necessidades específicas, sem precisar saber codificar. Já disse que meu parâmetro aqui é meu filho de 16 anos que usa o chat todo dia. Ele sentou comigo na sexta e fizemos um chat personalizado, que recebe um texto escrito por ele e o corrige usando os padrões estabelecidos pela escola. Fizemos um teste e as recomendações são muito mais precisas comparando o modelo “normal” e o modelo “international school”. E ele pode compartilhar isto com os colegas, é uma versão em esteroides dos prompts customizados. A OpenAI entendeu que o usuário comum precisa ter sua vida facilitada.

Outro exemplo disto é a possibilidade de enviar anexos (no momento, limitado a 10 arquivos). Antes você precisava usar um plugin, que enviava o documento para um serviço e a partir dai o ChatGPT analisava. Testamos isto com um arquivo de dados meteorológicos, 80MB e zipado em bzip. Ele foi capaz de abrir o arquivo e fazer as análises. O que me leva a outra novidade, o agente “Data Analysis”. Isto já podia ser feito antes, mas este chat personalizado torna ainda mais fácil descobrir tendencias, anomalias. Naquele meu arquivo, eu devo admitir que os gráficos que ele montou ficaram melhores que os meus ¯\_(ツ)_/¯

E para o mundo corporativo, duas mensagens: Sam frisou que o ChatGPT Enterprise não usa as informações submetidas para treinamento do modelo, i.e., não ha o risco da sua planilha com os dados de venda do ultimo trimestre aparecer para o seu concorrente. E que a OpenAI tem uma iniciativa, chamada “Copyright Shield”, em que ela irá arcar com custos jurídicos de acoes por violação de direitos autorais. A empresa defende seu uso de dados sob a alegação de “fair use” sob a lei de direitos autorais dos EUA, uma norma que permite uma interpretação mais liberal da lei de direitos autorais em sintonia com os ideais americanos de livre expressão.

Excitante!

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.

Radar de Tecnologia

Uma nova edição do Technology Radar da ThoughtWorks foi publicada ontem

https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2023/09/tr_technology_radar_vol_29_en.pdf

Para surpresa de ninguém, IA é o grande tema desta edição, eu entretanto fui atraído por 2 itens:

Mermaid

Mermaid está no quadrante de adoção.

https://mermaid.js.org/

No meu projeto atual usamos documentação-como-código desde o inicio, exceto que a nossa escolha foi PlantUML. O que eu posso comentar da minha experiência, em 3 aspectos:

  • Consistência: Ao tratar a documentação como código, torna-se mais fácil manter a consistência entre o código e sua documentação, especialmente no que tange à arquitetura de software. Utilizamos C4 e quando fazemos mudanças estruturais, os diagramas e o novo código são versionados no mesmo PR, mostrando exatamente a evolução do sistema;
  • Colaboração: Entre engenheiros é ótimo pois soa mais natural editar a documentação no mesmo fluxo com que o software é editado. Fora do mundo dos engenheiros, há uma barreira pois é necessário saber o markup e uma interface point-and-click é mais intuitiva. Isto fica evidente na discussão do contexto do software, em que é necessária a interação com os colegas de negócio;
  • Automação: Aqui é o ponto em que a documentação-como-código brilha. Se a cultura dos times incentiva comentários no seu codebase, vários diagramas podem ser gerados automaticamente.

Complexidade

Para mim é difícil concordar com o argumento de que devemos abraçar a complexidade em desenvolvimento de software. Complexidade é algo que deve ser combatido no seu design, na sua implementação, no seu processo. Utilizando o Cynefin, nosso objetivo é transicionar do complexo para o complicado e, veja, o artigo utiliza AI como um exemplo de complexidade porém AI opera no complicado, ao utilizar padrões e conhecimento para tomar decisões.

Neste tópico, eu lembro do Dumbledore falando para o Harry: “Soon we must all face the choice, between what is right and what is easy”. O trabalho de um arquiteto, e todos os engenheiros são arquitetos em alguma escala, é resistir à tentação da solução fácil; é comum nestas situações introduzir complexidade acidental. Se estamos falando de complexidade essencial, ok, ainda assim, devemos lutar para diminuí-la. Mas eu não culpo a ThoughtWorks pela abordagem, o Dijkstra já dizia “complexity sells better”.

https://www.thoughtworks.com/en-us/insights/blog/technology-strategy/why-embracing-complexity-real-challenge-software-today

Leiam o Radar, sempre é interessante especialmente confiram o que está próximo do nível de adoção.

APIDays

Esta semana estive em Londres atendendo o evento ApiDays. Uma vez ao ano eu participo de um evento externo, em adição a estudar sozinho, é importante encontrar colegas de profissão e conversar sobre o que acontece nas trincheiras. Para a minha surpresa, IA não foi o tema central, assisti por volta de 30 palestras e apenas 4 eram especificamente sobre IA. Dois grandes temas no evento:

Governança de API’s: Ênfase dada ao ciclo de vida das API’s: definição->design->desenvolvimento-> testes->publicação->operação. O que eu vou levar para casa:

  • A importância da documentação, ela é o ponto central da sua API, seja ela consumida pelos desenvolvedores, seja ela lida por robôs.
  • O papel dos padrões no design. Este é um mercado em ascensão e seus consumidores esperam que você siga OpenAPI, AsyncAPI, Semantic Versioning, HTTP response codes, Protocol Buffers definition language.
  • Sua operação tem que prever liberdade de escolha, não assuma um cloud provider, não force um gateway.

Democratização de API’s: Aqui há 2 visōes que estão convergindo, por um lado experts dizem que devemos desenvolver as API’s pensando em devops e gitops. Esta visão coloca uma grande importância nos aspectos de governança mencionados no item anterior; em adição, esta visão ressalta interoperabilidade e composibilidade como atributos essencias para API’s modernas. Por outro lado, se olharmos para a composição mais comuma das empresas, apenas 10% são da área de tecnologia (pesquisa da Gartner exibida em uma das palestras); temos 49% de usuários finais e 41% classificados como analistas de negócio tecnólogos. Estes 41% criam soluções de tecnlogia ou de análise a partir das soluções que a área de TI fornece. Eles cunharam o termo ‘mundo da economia pós-API’ para abraçar este pessoal que tem ter acesso facilitado às API’s. Quanto mais simples for, mais fácil será para produtos inovadores surgirem a partir da informação disponível. Esta segunda visão aposta em API’s abertas e públicas, aposta em ecossistemas e marketplaces.

Vou citar 2 ferramentas que testei no evento e achei fantásticas:

Superface.ai: OK, existem catálogos de API’s, sabemos do conceito de observabilidade, como lidar com API’s que são similares porém com formatos diferentes? Pense no wttr.in e no OpenWeatherMap, ambas permitem que você veja se vai chover hoje em Londres. Mas a similaridade termina aí, é necessário fazer o código para cada uma delas. Mais, se uma delas estiver indisponível você é responsável por rotear o pedido. O Superface lida com isto: (1) você fala qual o seu contrato (2) o Superface tem agentes autônomos que descobrem API’s condizentes com o seu contrato e mapeia o seu contrato para o contrato das API’s que ele localizou. (ok, aqui tem IA 🙂)

Mocking servers do Postman: eu uso Postman frequentemente para testar API’s, e descobri que nele você pode prototipar a sua API. Desenhe seus métodos, especifique os contratos a partir de exemplos e o Postman cria a documentação e um endpoint. Quando eu queria pensar em uma API, usava o httpbin, isto é muuuito mais bacana.

Home Office

Em 2008 eu trabalhava no Itaú na TI de Mercado de Capitais. Era parte de um time responsável por relatórios de performance de fundos, usados pelos traders para guiar suas estratégias. Nosso suporte era 24×7, especialmente durante a madrugada quando estes relatórios eram gerados. Discutimos se seria possível trabalhar em casa para o engenheiro responsável pelo stand-by; nosso pedido foi negado sob a justificativa de que era mais produtivo trabalhar na infra do banco, onde tudo estava disponível e onde todos os engenheiros de stand-by estavam. Veio 2020, Covid e sabemos o resultado: trabalhamos muito bem em nossas casas. Minha experiência e de colegas: trabalhamos melhor em nossas casas.

O Zoom cresceu exponencialmente justamente neste nicho e na semana passada lemos que seu CEO prefere trabalho presencial. Eric Yuan aponta velocidade de inovação e interação como motivadores, entrelinhas leia-se ‘nossa produtividade precisa aumentar’, de novo ela. Também nas entrelinhas eu leio que no Zoom o alto comando não confia nas pessoas exceto quando elas estão por perto para eu ver o que elas estão fazendo. A Microsoft mostrou isto neste Pulse Report de 2022:
“The majority of employees (87%) report that they are productive at work (…)” but “85% of global business decision makers say that the shift to hybrid work has made it challenging to have confidence that people are being productive”.

Trabalho em TI, este é o mundo que eu conheço e sobre o qual posso opinar. Aqui, engenheiros são produtivos trabalhando em casa e há dúvidas no C-level. A McKinsey deu voz a este sentimento e trouxe sua ideia há 2 semanas: Yes, you can measure software developer productivity. Kent Beck escreveu sobre isto na sua newsletter. Dada aquela crise de confiança que eu citei, são propostas métricas para medir o que estou fazendo. Kent é preciso na sua análise, eu concordo: eles confundem “atividade” com “produtividade”. Produtividade é sobre entregar valor e sobre transformar a sua empresa.

A dicotomia trabalho remoto X trabalho presencial não deveria ser a discussão central, confiança e produtividade são os elementais centrais. E ademais, você quer voltar para o escritório todos os dias?

Arquitetura e IA

Quando escrevi minha tese de Mestrado, conceituar Criatividade era essencial e usei as ideias de J.P. Guildford como base: criatividade é a capacidade de exibir comportamento criativo em um grau notável. Ele conceituou a criatividade como um fator dentro de uma teoria geral da inteligência, envolvendo o pensamento divergente que poderia ser desenvolvido através da interação entre indivíduos e seus ambientes. Sua proposta utiliza ciclos divergentes, que possibilitam a criação de alternativas para um problema de design a partir de várias perspectivas e o ciclos convergentes, enfatizando a melhor opção para o problema, sem margem para ambiguidade.

Tenho revisitado este tema discutindo no Reddit se o ChatGPT pode ser considerado criativo e cada vez mais tendo a dizer “Sim”. Mês passado um arquiteto sugeriu-me o livro “Architecture in the Age of Artificial Intelligence-An introduction to AI for architects“; afinal, um arquiteto deve ter ideias originais, ele poderia ser substituído pelo ChatGPT? É um livro curto (180pp) e recomendo a leitura, os 2 primeiros capítulos são um resumo de técnicas e como chegamos até aqui no campo de Inteligência Artificial (mas não espere nada em profundidade). Os demais capítulos oferecem a visão de que trabalhadores do conhecimento como arquitetos serão auxiliados por ferramentas de IA mas também podem ser superados por elas. E que é necessário antecipar e compreender onde isto acontece e preparar-se. Os relatos sobre a XKool são fascinantes e este artigo da Guardian tem imagens ótimas. Na minha leitura, o livro considera IA capaz de ser criativa, algo que a última newsletter do Nick Cave desmonta. Segundo Nick, “ChatGPT está acelerando a mercantilização do espírito humano ao mecanizar a imaginação”, para mim soa como anacrônico.

Eu, como desenvolvedor de software, também enxergo-me como trabalhador do conhecimento e tenho estudado muito para estar pronto. Tenho usado também meus filhos e seus amigos para (tentar) entender como a próxima geração projeta o mundo em alguns anos. Ambos vêem um mundo dominado por IA e receosos do lugar deles neste mundo. Digo a eles o que escrevi acima: estejam preparados.

Cypress, new kid on the block

Selenium tem sido minha ferramenta de escolha para automação de testes de UI por um bom tempo, e com razão. Ele foi o pioneiro e eu usei muito, mas recentemente tornei-me um fā do Cypress. Eu fiz um curso sobre Cypress (todos os exercícios podem ser encontrados no meu GH), e me convenci completamente de que ele apresenta uma alternativa mais eficiente e confiável.

Ao analisar as diferenças entre Selenium e Cypress, alguns fatores-chave se destacam. Selenium suporta várias linguagens incluindo Java, Python, C#, e outras enquanto Cypress é puramente JavaScript. Isso pode inicialmente parecer limitante, mas considerando que a maioria das aplicações web são agora baseadas em JavaScript, Cypress se torna uma escolha natural. Testes Selenium são executados fora do navegador enquanto Cypress roda diretamente dentro do navegador. Isso permite ao Cypress controlar todo o processo de automação, incluindo tráfego de rede, temporizadores e até mesmo o carregamento do código JavaScript. É este controle interno que promete estabilidade – uma promessa que o Selenium muitas vezes não consegue manter devido à suas dependências externas. A possibilidade de testar sua automação com opções de debugger no navegador é revolucionária, passo muito tempo entendendo meus scripts usando as abas do console, styles e rede, tenho certeza de que os desenvolvedores FE estão muito familiarizados com elas.

Cypress fornece uma API simples e fluida para interagir diretamente com o DOM, dê uma olhada:

describe('DOM Interactions Test', function() {
  it('Fills and submits a form', function() {
    cy.visit('https://www.example.com/form') // Cypress loads the webpage

    cy.get('input[name="firstName"]').type('John') // Cypress finds the input field firstName and types 'John' into it
    cy.get('input[name="lastName"]').type('Doe') // Cypress finds the input field lastName and types 'Doe' into it

    cy.get('button[type="submit"]').click() // Cypress clicks the submit button
  })
})

Compare com Selenium

WebDriver driver = new ChromeDriver();

driver.get("https://www.example.com/form"); // Open URL 

WebElement firstName = driver.findElement(By.name("firstName"));
firstName.sendKeys("John"); // Fill the firstName input

WebElement lastName = driver.findElement(By.name("lastName"));
lastName.sendKeys("Doe"); // Fill the lastName input

WebElement submitButton = driver.findElement(By.tagName("button")); 
submitButton.submit(); // Submit the form

Cypress permite que você interaja com seletores CSS!

Outra grande vantagem do Cypress é sua capacidade de lidar com operações assíncronas muito facilmente.

describe('Asynchronous Handling Test', function() {
  it('Waits for an element to be visible', function() {
    cy.visit('https://www.example.com') // Cypress loads the webpage

    cy.get('#asyncButton', { timeout: 10000 }) // Cypress waits for the element with id 'asyncButton' to become visible for up to 10 seconds
      .should('be.visible') // Asserts that the element should be visible
      .click() // Clicks the button once it's visible
  })
})

Lidar com API’s também é moleza:

describe("Todo List API Interaction", () => {
  // Define the base URL of your API
  const apiUrl = "https://example-api.com";

  beforeEach(() => {
    // Intercept the API call and load a JSON payload for the response
    cy.intercept("GET", `${apiUrl}/todos`, { fixture: "todos.json" }).as("getTodos");
    // Visit the application or a specific page where the API call is made
    cy.visit("/todo-list");
  });

  it("should fetch todos from the API and display them", () => {
    // Perform any actions that trigger the API call (e.g., click a button to fetch todos)
    cy.get("#fetch-todos-btn").click();

    // Wait for the API call to complete and the response to be displayed
    cy.wait("@getTodos");

    // Assert that the correct API endpoint was called and the response was handled properly
    cy.get(".todo-item").should("have.length", 3); // Assuming the response contains 3 todo items
  });
});

O que para mim é o grande atrativo é a minha ressalva: ao interagir a partir dos seletores CSS demanda que você seja cuidadoso ao escolher aqueles que têm menos chance de mudar e quebrar seus testes. Ainda assim, eu pretendo apenas usar Cypress para meus testes de UI.

Filtros de Bloom

Uma das minhas estruturas de dados favoritas para operações de busca eficientes é o filtro de Bloom, acabei de encontrar esta demonstração, confira lá.

Nomeado em homenagem ao seu criador, Burton Howard Bloom, um filtro de Bloom é uma estrutura de dados probabilística eficiente em termos de espaço, projetada para responder a uma pergunta simples: “Este item está no conjunto?”. Ao contrário de outras estruturas de dados, um filtro de Bloom compensa a precisão pela velocidade e eficiência de espaço, o que significa que às vezes pode retornar falsos positivos, mas nunca falsos negativos.

O filtro de Bloom funciona usando um vetor de bits de tamanho ‘m’ e ‘k’ funções de hash. Quando um elemento é adicionado ao filtro, ele é passado por todas as ‘k’ funções de hash, que retornam ‘k’ índices para definir como ‘1’ no vetor de bits. Para verificar se um elemento está no filtro, as mesmas ‘k’ funções de hash são aplicadas. Se todos os ‘k’ índices no vetor de bits forem ‘1’, o filtro retorna ‘sim’; caso contrário, retorna ‘não’. Uma resposta ‘sim’ pode significar que o elemento definitivamente não está no conjunto (verdadeiro negativo) ou pode estar no conjunto (falso positivo), mas uma resposta ‘não’ sempre significa que o elemento não está no conjunto (verdadeiro negativo). Note que ao implementar você deve pensar cuidadosamente quantas funções de hash utilizar e qual a taxa aceitável de falsos positivos.

Filtros de Bloom são amplamente utilizados em aplicações de software onde o custo de falsos positivos é menos crítico do que os benefícios de velocidade e eficiência de espaço. Algumas dessas aplicações incluem corretores ortográficos, roteadores de rede, bancos de dados e caches. Eu tenho um aplicativo gerador de senhas e uso Filtro de Bloom para verificar se uma senha já foi usada.