Showing posts with label português. Show all posts
Showing posts with label português. Show all posts

Sunday, April 25, 2021

List of posts

I'm always reading posts, articles, and papers from various sources on the Internet. In the last 4 years I have developed the habit of collecting the texts that are most relevant to me, and now that I've reached the number of 100 posts collected I think it's a good time to share them with you. I have divided them into some broad categories. The categories are organized in alphabetical order, although the posts themselves do not follow a specific order. Most of the texts are in English and some of them are in Portuguese. Enjoy!

APIs

  1. Best Practices for Designing a Pragmatic RESTful API
  2. API Gateways are going through an identity crisis
  3. API Versioning Has No "Right Way"

Architecture

  1. Unifying Mobile Onboarding Experiences at Uber
  2. What do you mean by "Event-Driven"?
  3. Focusing on Events
  4. 11 erros comuns em arquiteturas orientadas a eventos e como evitá-los
  5. Event Collaboration
  6. ParallelChange
  7. The evergreen cache
  8. The LMAX Architecture
  9. A primer on functional architecture
  10. A Brief History of Scaling LinkedIn
  11. The Architect Elevator — Visiting the upper floors
  12. BLIKI: Arquitetura de Software — EximiaCo.Tech

Blockchain

  1. WTF is The Blockchain?
  2. Who owns the Blockchain?

Carreer and personal development

  1. Programmer Competency Matrix
  2. LimitationsOfGeneralAdvice
  3. SoftwareDevelopmentAttitude
  4. Your obsession with learning might be holding you back
  5. How to get experience as a software engineer
  6. On Being A Senior Engineer
  7. What does sponsorship look like?
  8. A forty-year career.
  9. Pendulum swings
  10. How to Disagree

Development tools

  1. How (and Why) to Log Your Entire Bash History
  2. Who Needs Git When You Got ZFS?

Documentation

  1. Como escrever boas documentações
  2. Etsy's experiment with immutable documentation
  3. The Golden Rules of Code Documentation
  4. Our team broke up with instant-legacy releases and you can too
  5. Undervalued Software Engineering Skills: Writing Well

Incident management

  1. Introducing Dispatch
  2. Blameless PostMortems and a Just Culture
  3. Three months, 30x demand: How we scaled Google Meet during COVID-19

Microservices and distributed systems

  1. Best Practices for Building a Microservice Architecture
  2. Standing on Distributed Shoulders of Giants
  3. The rise of non-microservices architectures
  4. Thinking about Microservices: The Fiefdom and the Emissaries
  5. Where is my cache? Architectural patterns for caching microservices by example
  6. Patterns for Microservices — Sync vs. Async
  7. The Hardest Part About Microservices: Your Data
  8. The Hardest Part of Microservices: Calling Your Services
  9. Introducing Domain-Oriented Microservice Architecture
  10. Seven Hard-Earned Lessons Learned Migrating a Monolith to Microservices
  11. Backend-in-the-frontend: a pattern for cleaner code
  12. The Log: What every software engineer should know about real-time data's unifying abstraction

People, teams, and processes

  1. The Agile Fluency Model
  2. Why Your Employees Are Losing Motivation
  3. Our obsession with performance data is killing performance
  4. Evidence Based Scheduling
  5. 3 Habits of a Highly Effective Growth Engineering Team
  6. The epistemology of software quality
  7. Building a Platform Team — Laying the Foundations
  8. Maximizing Developer Effectiveness
  9. front-of-the-front-end and back-of-the-front-end web development
  10. Embrace the Grind

Product

  1. Design for the Novice, Configure for the Pro
  2. Once You’ve Solved for the Novice, You Need to Handle the Pro
  3. When a rewrite isn’t: rebuilding Slack on the desktop

Programming languages, design, and implementation

  1. Revenge of the Nerds
  2. Things You Should Never Do, Part I
  3. Python Design Patterns: For Sleek And Fashionable Code
  4. The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
  5. Efficiently Exploiting Multiple Cores with Python
  6. Python 3 Q & A
  7. DRY is about Knowledge
  8. Domain-Driven Design is Linguistic
  9. GoF Design Patterns — Sobreviveu ao teste do tempo?
  10. Design patterns of 1972
  11. Ralph Johnson on design patterns
  12. "Design Patterns" Aren't
  13. Monopólio de linguagens: uma perspectiva além de tecnologia
  14. Programming as translation
  15. Short Identifier
  16. Crash-only software: More than meets the eye
  17. Ignore All Web Performance Benchmarks, Including This One
  18. Too DRY — The Grep Test
  19. The Right Way to Bundle Your Assets for Faster Sites over HTTP/2
  20. Collection Pipeline

Security

  1. So you want to secure something
  2. Up to 20% of your application dependencies may be unmaintained

Technical debts

  1. Chernobyl: The True Cost Of Technical Debt
  2. Three Tips for Managing Technical Debt: While Maintaining Developer Velocity (and Sanity)
  3. When Your Tech Debt Comes Due
  4. TechnicalDebtQuadrant

DevOps

  1. 5 Lessons Learned From Writing Over 300,000 Lines of Infrastructure Code
  2. Monitoring Check Smells
  3. The Calculus of Service Availability
  4. How to invest in technical infrastructure
  5. Why Google Stores Billions of Lines of Code in a Single Repository

Technology and history

  1. True Innovation
  2. The Secret History of Women in Coding
  3. The Yoda of Silicon Valley

Tests and quality

  1. Software Testing Anti-patterns
  2. Is High Quality Software Worth the Cost?
  3. The Rise of Test Impact Analysis
  4. I test in prod

Thursday, April 1, 2021

Lista de podcasts

Podcasts têm crescido bastante em audência no mundo todo e ganhado cada vez mais espaço no Brasil. Desde que descobri essa mídia, passei a integrá-la também à minha rotina, como mais uma fonte de conhecimento. É uma ótima maneira, por exemplo, de aproveitar o tempo gasto em tarefas mais mecânicas (como limpar a casa, lavar a louça, dirigir ou caminhar) para consumir novos conteúdos e aprender um pouco mais. Eventualmente escuto episódios isolados de certos podcasts, seja por indicação de alguém que conheço ou por esbarrar com algo na Internet que me chama a atenção. No entanto, existem alguns podcasts que acompanho com regularidade, e são esses que compartilho na lista a seguir:

  • Hipsters Ponto Tech: é o podcast de tecnologia que acompanho há mais tempo (desde que surgiu, em 2016). Com temática diversa, hosts muito simpáticos e ótimos convidados, o Hipsters consegue atingir um bom equilíbrio entre informação e entretenimento. Os episódios do Hipsters On The Road, spin-off do podcast, também são muito bons.
  • DEVNAESTRADA: embora possua alguns episódios mais técnicos sobre tecnologias específicas, o forte do DEVNAESTRADA é o foco no cotidiano de quem trabalha com desenvolvimento de software, falando tanto de aspectos profissionais (como carreira, processos e ferramentas) quanto de aspectos pessoais (como saúde, hábitos e motivações). Nos episódios de entrevistas é possível escutar histórias de vida inspiradoras de pessoas que trabalham com tecnologia dentro e fora do Brasil.
  • Lambda3 Podcast: com um feed variado, o podcast da Lambda3 também consegue atingir um bom equilíbrio entre densidade de informação e uma apresentação leve e divertida. Os podcasts técnicos são bem embasados, representando hoje uma das grandes referências nacionais em tecnologia.
  • Naruhodo: um dos podcasts que mais gosto de ouvir. Naruhodo alia curiosidades do dia-a-dia com ciência, apresentando os assuntos com muito bom humor sem abrir mão da corretude científica. Não é um podcast de tecnologia, mas muitas das informações podem ser aplicadas nesse contexto também.
  • Software Engineering Daily: o único da lista em inglês e provavelmente o mais técnico de todos. Jeff Meyerson entrevista profissionais de alto nível da indústria de software a fim de destrinchar tecnologias e abordagens específicas.

Wednesday, January 8, 2020

Logs em formato JSON com Python

Python possui um módulo de logging bastante robusto já embutido em sua biblioteca padrão. Esse módulo disponibiliza muita coisa pronta para que qualquer pessoa comece a incluir logs em sua aplicação sem grande esforço. Não obstante, o módulo é também altamente configurável, permitindo personalizar a estrutura de handling dos logs, o formato das mensagens, entre outras coisas.

Em algumas situações, pode ser interessante que a mensagem de log gerada seja um JSON bem formatado, contendo informações sobre o fluxo da aplicação em formato chave-valor. Isto é, em vez de emitir logs esparsos, que teriam que ser agregados para dar visão geral do fluxo, poderíamos ter um único log em formato JSON impresso ao final da execução de determinado fluxo (independentemente desse fluxo ter terminado de forma bem sucedida ou não). Essa abordagem facilita não somente a busca por mensagens específicas (usando ferramentas como o CloudWatch Logs Insights) mas também o próprio processo de depuração de problemas, concentrando as informações necessárias num formato bem estruturado.

Em Python, podemos gerar strings JSON a partir de dicionários. Usando as cláusulas try/except/finally, consequimos também garantir a impressão dos logs qualquer que seja o resultado da execução do fluxo contido no bloco de tratamento de exceções. A maior dificuldade é repetir todo esse boilerplate nos pontos em que é necessário aplicar o log JSON. Podemos então lançar mão de mais um recurso da linguagem a fim de evitar essa repetição: decoradores. O Gist a seguir mostra uma maneira de conectar todas essas ideias para construir um decorador que, ao ser aplicado a um método/função, permite construir facilmente um log JSON que será impresso ao final da execução desse método/função, ainda que um erro aconteça durante a execução.

Tuesday, December 24, 2019

Evitando chamadas custosas em testes automáticos

Ao escrever testes automáticos, é comum utilizarmos Test Doubles para substituir dependências diretas do código sob teste. Além de ter impacto direto na forma de pensar e construir tanto os casos de teste quanto o próprio código sob teste, essa prática também permite eliminar chamadas custosas e/ou não confiáveis durante a execução dos testes, garantindo assim mais eficiência e confiabilidade para a suíte de testes como um todo.

Por exemplo, suponha que precisemos testar uma função ou objeto que efetue uma requisição HTTP para uma API externa à nossa aplicação. Podemos criar um mock para o trecho de código que faz a requisição, de forma a simular o retorno esperado e, assim, não ter que fazer a chamada real de rede. Ganhamos em eficiência, pois, sem a requisição, não é necessário lidar com a latência de rede durante a execução dos testes. Ganhamos também em confiabilidade, pois, como chamadas HTTP podem falhar, qualquer requisição externa tem o potencial de gerar um falso positivo na suíte de testes; removendo a chamada, removemos essa possibilidade.

Pensando nisso, é de vital importância que numa base de código grande — com uma suíte de testes, em geral, igualmente grande — consigamos automaticamente garantir que chamadas custosas sejam apropriadamente mockadas. No caso de requisições de rede, podemos simplesmente bloquear ou restringir chamadas de socket durante a execução dos testes. É o que o pytest-socket, por exemplo, faz. Para quem usa o pytest, basta instalar o plugin e executar pytest --disable-socket. Qualquer teste em que uma chamada de socket for feita (mesmo por pacotes terceiros importados) irá falhar com SocketBlockedError.

Para códigos com custo de computação alto (ex: uma função com um pesado cálculo recursivo) que façam parte da aplicação, uma forma de evitar seu uso sem mock em testes é torna esse requisito uma parte do próprio código, isto é, permitir que a pessoa que o desenvolveu adicione alguma marcação que bloqueie a chamada em ambiente de teste. Não conhecendo uma solução já existente para isso em Python, me aventurei em criar a minha própria e daí surgiu o decorador enforce_mock_in_tests. Esse decorador pode ser aplicado a classes ou funções. A cada chamada do código decorado, ele avalia se o ambiente é de teste ou não e, se for, uma exceção é lançada, dando uma clara indicação ao desenvolvedor de que aquele código não deve ser chamado diretamente nos casos de teste, mas sim mockado. Além do código do decorador em si, o Gist abaixo contém também um arquivo com casos de teste para ele, permitindo ver como o decorador pode ser usado no código da aplicação.

Sunday, August 6, 2017

Aprendendo a aprender

Recentemente, ouvi a entrevista do Fabio Akita no DEVNAESTRADA e fiquei bastante admirado com a sua história, seu conhecimento e sua visão. Em particular, achei especialmente pertinentes os comentários dele sobre a necessidade de aprendermos a aprender (isto é, de cultivarmos uma mentalidade de estudo, crescimento e evolução constantes) e sobre o papel do verdadeiro engenheiro, que é o de resolver problemas, não o de se tornar um defensor de ferramentas (algo na mesma linha do que comentei sobre trade-offs). Vale a pena escutá-lo relatando sua trajetória e compreender como ele aplica essas filosofias ao seu método de trabalho.

Wednesday, May 24, 2017

Trade-off: a única medida razoável

Engenharia de software envolve decisões. Decisões sobre organização, decisões sobre processos e, principalmente, decisões sobre tecnologia. No caso dessas últimas,  as opções em cada nível costumam ser muitas, desde a escolha do sistema operacional até a escolha da plataforma de hospedagem, passando por linguagens de programação (ou mais precisamente línguas, em homenagem ao meu colega Evandro), frameworks, tipos de armazenamento de dados, entre outras coisas.

Nesse cenário, discutir cada opção torna-se extremamente valioso. Mas pode tornar-se também um mero exercício de reforço de preferências pessoais, dependendo da postura das pessoas envolvidas. Aliás, é bastante comum entrarmos numa reunião desse tipo e constatarmos que ela rapidamente começa a se assemelhar mais a um jogo de futebol, com cada um torcendo apaixonadamente pela vitória da sua tecnologia preferida, do que a uma avaliação científica e imparcial, como deveria ser.

Ter preferências é absolutamente normal, não se pode impedir que cada um se sinta mais confortável usando determinada tecnologia em lugar de outras. O problema começa quando essa inclinação pessoal interfere a tal ponto que o engenheiro ou desenvolvedor não consegue perceber os pontos fracos daquilo que gosta e defende. Consequentemente, ele passa também a não conseguir apreciar os pontos fortes de outras abordagens. Por fim, essa postura culmina numa incapacidade de discernir quando e como aplicar cada tecnologia a favor do objetivo do projeto. Com isso, o indivíduo acredita plenamente que as tecnologias de sua preferência servem para resolver qualquer problema, não importa as circunstâncias. Da mesma forma, menospreza todas as outras propostas, sem se dar ao trabalho de refletir a respeito. É nessas horas que ouvimos frases como "Pra quê discutir sobre isso? Basta usar X e pronto, está resolvido!" ou "Usar Y? Jamais!".

Recentemente, conversando o Myhro, meu colega de trabalho, sobre esse assunto, ouvi dele um comentário que sintetiza bem a minha opinião a respeito: em se tratando de escolha de tecnologias, o trade-off é a única medida razoável. Em outras palavras, não importa o quanto você goste de X ou Y, na hora de tomar decisões sobre qual tecnologia usar, é preciso recorrer à boa e velha lista de prós e contras, levando sempre em conta o resultado que deve ser atingido. Essa é a postura analítica e científica que se espera de todo bom profissional da área de computação.

Monday, March 27, 2017

The book is on the table. Bom, nem sempre, mas ele ainda é importante

Sempre gostei de ler. Desde pequeno, lembro de me encantar com as histórias nos livros. Com o tempo, passei a apreciar tipos variados de literatura, incluindo os livros técnicos. Quando entrei na universidade e tive acesso àquela enorme rede de bibliotecas dos diversos prédios, foi como se um mundo inteiro de conhecimento se abrisse diante de mim, inteiramente  à disposição. E até hoje, o acesso à biblioteca é uma das coisas que mais sinto falta das minhas épocas de graduação e mestrado.

De todo modo, o gosto pela leitura persiste e, de volta ao mercado, sigo buscando bons livros para me aperfeiçoar. Hoje me espanto com a quantidade de títulos disponíveis, muito graças à facilidade de distribuição que a Internet trouxe, revolução comparável à que Gutenberg causou na produção de livros com sua máquina de tipos móveis. A propósito, o gráfico alemão ficaria certamente admirado ao ver como a imprensa evoluiu desde sua invenção, chegando aos limites de podermos consultar milhares de livros num dispositivo que cabe na palma da mão.

Igualmente espantoso, porém, é notar o pouco interesse de colegas de profissão pela leitura de livros técnicos. De maneira geral, não vejo desinteresse por ler e se informar, mas noto que os livros não estão entre as primeiras opções de aquisição de conhecimentos. Blogs, artigos de sites, artigos científicos e tutoriais entram na frente. Por que isso acontece?

Entendo perfeitamente que, sendo a computação uma área extremamente dinâmica, é fácil acontecer de conteúdos escritos sobre assuntos mais específicos se tornarem rapidamente obsoletos e isso, consequentemente, desencorajar certos investimentos, pois ninguém quer ter a sensação de estar jogando tempo fora ao ler um livro de 700 páginas que pode estar ultrapassado daqui a seis meses. Entendo também que esse mesmo dinamismo pode colocar uma certa pressão nas escolhas do que vamos ler: tem tanta coisa sendo lançada e mudando o tempo todo que, pra quem deseja estar na "crista da onda", há material suficiente de leitura nos blogs e artigos para preencher praticamente todo o tempo disponível.

Ainda assim, me questiono se esses dois motivos são suficientes para reduzir a utilidade dos livros técnicos e relegá-los a segundo, terceiro ou quarto planos, como vejo acontecer com tanta frequência. Tenho a impressão de que o problema reside mais na escolha dos livros para ler do que na leitura de livros em si.

No caso do primeiro problema que citei, se, por um lado, existem livros que tendem a ser focados no momento, perdendo muito de seu valor dentro de meses ou anos, existem também aqueles que podemos considerar atemporais. Eles tocam em questões de base, pertinentes à essência de tarefas em computação. Com isso, possuem o poder de se conservar úteis mesmo depois de anos ou décadas, ainda que algumas de suas partes fiquem desatualizadas. Esse poder compensa o esforço da leitura e retribui o investimento de tempo, por maior que seja. Não por acaso, considero que esse mesmo tipo de livro tem o poder de se colocar em patamar de igualdade (se não superior) com os conteúdos da "crista da onda". Isso porque todo conteúdo recente, toda novidade, partiu de construções anteriores. Assim, entender essas construções e, principalmente, a base comum a elas, ajuda imensamente a entender o que as novidades propõem, quais benefícios trazem em relação ao que existe e quais dificuldades acarretam (afinal, there is no free lunch).

Existe, portanto, um tipo de livro capaz de fazer frente aos impeditivos mencionados anteriormente: o livro atemporal, de base (alguns usariam o termo "clássico", mas não creio que essa palavra comunique exatamente o quero dizer). E esse tipo de livro ainda é importante, ainda vale a pena ser lido, seja no exemplar impresso ou em mídia digital. Ao fazer essa afirmação, não tenho a intenção de diminuir a relevância de conteúdos publicados em blogs, artigos e tutoriais (este texto, inclusive, faz parte de tal conjunto). Apenas exorto colegas de profissão a considerarem o quanto podem ganhar retomando os laços com esse antigo amigo: o livro.

Sabendo, contudo, que exortações raramente funcionam tão efetivamente como o exemplo, pretendo adotar a mesma postura de Fred Brooks [1] e concentrar esforços no "como", isto é, comentando a respeito de bons livros que, em minha opinião, se encaixam na categoria que descrevi. É o que virá em futuros posts.

[1]
Frederick P. Brooks, Jr.. The Other Face. In: ______. The Mythical Man-Month
(Anniversary Ed.)
. Boston: Addison-Wesley, 1995. Cap. 15, p. 164.