<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marcio Frayze</title>
    <description>The latest articles on DEV Community by Marcio Frayze (@marciofrayze).</description>
    <link>https://dev.to/marciofrayze</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F202418%2Fc9f97a40-a3cb-4d62-969e-7aa1a19ec2ea.jpeg</url>
      <title>DEV Community: Marcio Frayze</title>
      <link>https://dev.to/marciofrayze</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marciofrayze"/>
    <language>en</language>
    <item>
      <title>What it was like to give a talk at Clojure South 2025</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Wed, 03 Dec 2025 14:45:59 +0000</pubDate>
      <link>https://dev.to/marciofrayze/what-it-was-like-to-give-a-talk-at-clojure-south-2025-b1c</link>
      <guid>https://dev.to/marciofrayze/what-it-was-like-to-give-a-talk-at-clojure-south-2025-b1c</guid>
      <description>&lt;h2&gt;
  
  
  What is Clojure South?
&lt;/h2&gt;

&lt;p&gt;According to the &lt;a href="http://clojure-south.com" rel="noopener noreferrer"&gt;official website&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Organized by Nubank, Clojure South is part of the official Clojure community schedule, connecting developers, enthusiasts, and companies to share real experiences, discuss trends, and strengthen the global network of the language." - Translated from Brazilian Portuguese by me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;In a conversation with a Brazilian woman I met at &lt;a href="https://www.lambdadays.org/lambdadays2025" rel="noopener noreferrer"&gt;Lambda Days 2025&lt;/a&gt; (I talked about what it was like to attend this event &lt;a href="https://dev.to/marciofrayze/how-was-my-experience-at-lambda-days-2025-2kc2"&gt;in this article&lt;/a&gt;), I asked if she would attend the conference (she works at Nubank) and found out she would be an instructor for the Clojure workshop. During this conversation, she suggested that I should submit a talk proposal. I mentioned an idea I had in mind but was feeling a bit insecure about sending it. She encouraged me to try, and I decided to take a chance!&lt;/p&gt;

&lt;p&gt;Although I already have &lt;a href="(https://segunda.tech/about)"&gt;some talks&lt;/a&gt; on my resume, I felt that maybe I should be more cautious in this case, and submit a proposal for a &lt;em&gt;lightning talk&lt;/em&gt; (a 10-minute talk with no time for questions).&lt;/p&gt;

&lt;p&gt;A few weeks later, to my surprise, the proposal was accepted!&lt;/p&gt;

&lt;h2&gt;
  
  
  Theme
&lt;/h2&gt;

&lt;p&gt;I had two possible topics in mind. One about teaching Clojure and Functional Programming to beginners (because of my course &lt;a href="https://segunda.tech/clojure" rel="noopener noreferrer"&gt;Clojure: Introdução à Programação Funcional&lt;/a&gt;; an Introduction to Functional Programming through Clojure, for Brazilians). And another about a project I built at the company where I work, using Clojure in the &lt;em&gt;backend&lt;/em&gt; and the programming language &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; for the &lt;em&gt;front-end&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I chose the second one. It was already a project I wanted to talk about publicly, and this seemed like a great opportunity!&lt;/p&gt;

&lt;p&gt;Another factor is that the project is related to a very well-known App in Brazil, the Digital Driver's License — an &lt;em&gt;App&lt;/em&gt; developed by &lt;a href="https://www.serpro.gov.br" rel="noopener noreferrer"&gt;SERPRO&lt;/a&gt; and available for &lt;a href="https://play.google.com/store/apps/details?id=br.gov.serpro.cnhe" rel="noopener noreferrer"&gt;Android&lt;/a&gt; and &lt;a href="https://apps.apple.com/br/app/carteira-digital-de-tr%C3%A2nsito/id1275057217" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;. I imagined this could increase the chances of the talk being accepted.&lt;/p&gt;

&lt;p&gt;The full description I submitted was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;During the development of the &lt;em&gt;Carteira Digital de Trânsito&lt;/em&gt; (Digital Driver's License), I realized how challenging it was to support an App with millions of users integrated with many systems. I dreamed of creating a simple, friendly internal interface for queries that would make support easier. That’s how &lt;strong&gt;&lt;em&gt;Apoio CDT&lt;/em&gt;&lt;/strong&gt; was born, a web system that automated processes and enabled fast and secure queries. With a Clojure backend and an Elm front-end, we developed an MVP in three weeks. The result was a simple, efficient, and easy-to-maintain web architecture over the years.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As far as I know, this was the company’s first project using Clojure and also the first using Elm. And it was the first time I had the opportunity to talk about this system to people outside the company where I work!&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Talks and Workshops
&lt;/h2&gt;

&lt;p&gt;The event lasted two days, and the first day featured the two workshops:&lt;/p&gt;

&lt;h3&gt;
  
  
  Clojure Workshop
&lt;/h3&gt;

&lt;p&gt;An introductory Clojure course, in English, taught by &lt;a href="https://www.linkedin.com/in/christoph-neumann-6089438/" rel="noopener noreferrer"&gt;Christoph Neumann&lt;/a&gt;, Clojure &lt;em&gt;Developer Advocate&lt;/em&gt; at Nubank.&lt;/p&gt;

&lt;p&gt;Although I already have experience with Clojure, it was great to reinforce the main concepts of the language and I even learned some fundamentals I didn’t know yet!&lt;/p&gt;

&lt;h3&gt;
  
  
  Datomic Workshop
&lt;/h3&gt;

&lt;p&gt;The afternoon of the first day was dedicated to the &lt;em&gt;workshop&lt;/em&gt; of the &lt;a href="https://www.datomic.com" rel="noopener noreferrer"&gt;Datomic&lt;/a&gt; database. It was taught in Brazilian Portuguese by &lt;a href="https://www.linkedin.com/in/aanacarolina/" rel="noopener noreferrer"&gt;Carolina Silva&lt;/a&gt; (the same one I mentioned at the beginning of this article) and &lt;a href="https://www.linkedin.com/in/hanna-f-mariano-59578596/" rel="noopener noreferrer"&gt;Hanna Figueiredo&lt;/a&gt;, both &lt;em&gt;Software Engineers&lt;/em&gt; at Nubank.&lt;/p&gt;

&lt;p&gt;I had already watched several talks about Datomic and always found it an intriguing and interesting database. I believe it would make a lot of sense to use it in several projects I have worked on or currently work on.&lt;/p&gt;

&lt;p&gt;The workshop covered many theoretical concepts of Datomic, but it was also very hands-on.&lt;/p&gt;

&lt;p&gt;You can check out the hands-on portion of the workshop &lt;a href="https://github.com/Datomic/day-of-datomic-conj" rel="noopener noreferrer"&gt;in this GitHub repository&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I confess it was a lot of information in a short time. I will definitely need to revisit the repository and practice a lot more to internalize the core concepts of this database. But it was totally worth it!&lt;/p&gt;

&lt;p&gt;If before I already thought studying this database was worthwhile, now I’m certain of it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conversations and Feedback
&lt;/h2&gt;

&lt;p&gt;Right when I arrived at the event, I had the chance to talk to some people I only knew online, such as &lt;a href="https://www.linkedin.com/in/arthur-fucher/" rel="noopener noreferrer"&gt;Arthur Fücher&lt;/a&gt;. Besides being a &lt;em&gt;Senior Software Engineer&lt;/em&gt; at Nubank, Arthur is very active in the Brazilian Clojure community!&lt;/p&gt;

&lt;p&gt;And even though I am quite shy, I was able to meet many great people from Brazil and other countries.&lt;/p&gt;

&lt;p&gt;In particular, I was welcomed &lt;strong&gt;very&lt;/strong&gt; warmly by Christoph Neumann. I was standing quietly in a corner during the &lt;em&gt;happy hour&lt;/em&gt;, after the second day of the event, eating and thinking about heading home, when he approached me and started a conversation. We talked a bit, and I began asking a few questions about Datomic. During the conversation, I mentioned that Datomic might be a good fit for the company where I work. When I said what the company does, he became very interested! And soon offered to introduce me to &lt;a href="https://www.linkedin.com/in/joe-lane-7674173a/" rel="noopener noreferrer"&gt;Joe Lane&lt;/a&gt;, &lt;em&gt;Principal Engineer Building Datomic&lt;/em&gt; at Nubank!&lt;/p&gt;

&lt;p&gt;I talked to Joe and, again, was very kindly received! He seemed genuinely excited when I mentioned where I worked and the types of projects SERPRO develops, and he offered to answer any questions about Datomic — even mentioning that SERPRO could be a great Datomic case study.&lt;/p&gt;

&lt;p&gt;During the event, I also had the opportunity to meet people who took &lt;a href="https://www.udemy.com/course/clojure-introducao-a-programacao-funcional/" rel="noopener noreferrer"&gt;my Clojure course&lt;/a&gt;! Among them, I met &lt;a href="https://www.linkedin.com/in/bruno-dobelin/" rel="noopener noreferrer"&gt;Bruno Guimarães&lt;/a&gt;, currently a &lt;em&gt;Senior Software Engineer&lt;/em&gt; at Nubank and the host of the conference.&lt;/p&gt;

&lt;p&gt;Meeting students of my online course in person is always a very special experience! The numbers, the stats, the comments — they gain a face, a voice, life. It's truly rewarding!&lt;/p&gt;

&lt;p&gt;On the second day, after my talk, many people came to talk and learn more about how I introduced Clojure into a federal government system in Brazil. Some had specific questions about my motivation for using &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; on the &lt;em&gt;front-end&lt;/em&gt; (instead of opting for ClojureScript), plus several other interesting conversations.&lt;/p&gt;

&lt;p&gt;The feedback was very positive, and all the conversations were friendly, fun, and respectful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Food (and More Conversations)
&lt;/h2&gt;

&lt;p&gt;The event had a &lt;em&gt;welcome coffee&lt;/em&gt; in the morning and &lt;em&gt;coffee breaks&lt;/em&gt; throughout the day. The quality was excellent and everything was quite formal (maybe a bit too formal? lol).&lt;/p&gt;

&lt;p&gt;For lunch, there were several options (not included in the ticket price) within the same building complex where &lt;a href="https://building.nubank.com/pt-br/escritorio-nubank-brasil-spark/" rel="noopener noreferrer"&gt;Nubank Sparks&lt;/a&gt; is located. This made things much easier, especially on the workshop day, since I had my laptop with me.&lt;/p&gt;

&lt;p&gt;You could eat wherever you wanted. But I liked the nearby options, and it became yet another opportunity to talk to more people from the event. Again, even being shy and sitting somewhere more secluded, several people soon came to sit with me and chat. At that moment, I met a Ukrainian attendee who showed us the &lt;em&gt;Diia&lt;/em&gt; App, where she can have digital versions of several documents such as her Driver’s License, Passport, and more — with access to over 130 government services (you can learn more about this App &lt;a href="https://en.wikipedia.org/wiki/Diia" rel="noopener noreferrer"&gt;on its Wikipedia page&lt;/a&gt;)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Was It Worth It?
&lt;/h2&gt;

&lt;p&gt;Definitely, yes!&lt;/p&gt;

&lt;p&gt;The event happened on two weekdays (a Monday and Tuesday). This may make it difficult for some people to attend — for example, a colleague of mine couldn’t go because his company didn’t allow him to take those days off. But for those who can attend, it’s far less tiring than having an event like this over the weekend after a long workweek.&lt;/p&gt;

&lt;p&gt;I had purchased the early-bird tickets before my talk was accepted, but later the event organizers refunded me — I received free tickets for both days as a speaker. They also offered help with transportation and lodging, which I declined since the event was close to where I live.&lt;/p&gt;

&lt;p&gt;The experience of speaking at an event of this magnitude, even if only for 10 minutes, was incredible! It’s a feeling of great gratitude to the people who organized the conference and who trusted in my potential!&lt;/p&gt;




&lt;p&gt;Did you like this article? &lt;strong&gt;Don't forget to leave a reaction!&lt;/strong&gt; They serve as a big incentive for me to write others.&lt;/p&gt;

&lt;p&gt;You can also discover more articles, podcasts and videos at: &lt;a href="https://segunda.tech/tags/english" rel="noopener noreferrer"&gt;https://segunda.tech/tags/english&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want, follow me on &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="https://staging.bsky.app/profile/segunda.tech" rel="noopener noreferrer"&gt;blue sky&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/marcio-frayze" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>nubank</category>
      <category>elm</category>
    </item>
    <item>
      <title>Como foi palestrar na Clojure South 2025</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Sun, 23 Nov 2025 21:40:28 +0000</pubDate>
      <link>https://dev.to/marciofrayze/como-foi-palestrar-na-clojure-south-2025-3hb3</link>
      <guid>https://dev.to/marciofrayze/como-foi-palestrar-na-clojure-south-2025-3hb3</guid>
      <description>&lt;h2&gt;
  
  
  O que é a Clojure South?
&lt;/h2&gt;

&lt;p&gt;Segundo &lt;a href="http://clojure-south.com" rel="noopener noreferrer"&gt;site oficial&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Organizada pelo Nubank, a Clojure South faz parte da programação oficial da comunidade de Clojure, conectando pessoas desenvolvedoras, entusiastas e empresas para compartilhar experiências reais, discutir tendências e fortalecer a rede global da linguagem."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivação
&lt;/h2&gt;

&lt;p&gt;Em uma conversa com uma brasileira que conheci na &lt;a href="https://www.lambdadays.org/lambdadays2025" rel="noopener noreferrer"&gt;Lambda Days 2025&lt;/a&gt; (falei sobre como foi participar deste evento &lt;a href="https://dev.to/marciofrayze/como-foi-minha-experiencia-na-lambda-days-2025-27k3"&gt;neste artigo&lt;/a&gt;), perguntei se ela iria assistir às palestras (ela trabalha para a Nubank) e descobri que ela iria ser instrutora do &lt;em&gt;workshop&lt;/em&gt; de Clojure! Nesta conversa ela sugeriu que eu deveria enviar uma proposta de palestra. Comentei uma ideia que eu tinha para submeter, mas que estava meio inseguro de enviar. Ela me encorajou a tentar e eu resolvi arriscar!&lt;/p&gt;

&lt;p&gt;Embora tenha no meu currículo &lt;a href="(https://segunda.tech/sobre)"&gt;algumas palestras&lt;/a&gt; e &lt;a href="https://segunda.tech/tags/podcast/" rel="noopener noreferrer"&gt;participações em podcasts&lt;/a&gt;, sentia que talvez fosse mais interessante, neste caso, submeter uma proposta no formato &lt;em&gt;lighting talk&lt;/em&gt; (palestra de apenas 10 minutos e sem tempo para perguntas).&lt;/p&gt;

&lt;p&gt;E algum tempo depois, para minha surpresa, a proposta foi aceita!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tema
&lt;/h2&gt;

&lt;p&gt;Havia pensado em enviar propostas sobre dois possíveis temas. Um sobre o ensino de Clojure e Programação Funcional para iniciantes (por conta do meu curso &lt;a href="https://segunda.tech/clojure" rel="noopener noreferrer"&gt;Clojure: Introdução à Programação Funcional&lt;/a&gt;). E outro sobre um projeto que fiz na empresa onde trabalho, que utiliza Clojure no &lt;em&gt;backend&lt;/em&gt; e a linguagem de programação &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; para o &lt;em&gt;front-end&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Optei pela segunda opção. Já era um projeto que eu queria falar sobre publicamente e esta parecia ser uma boa oportunidade! &lt;/p&gt;

&lt;p&gt;Outro fator é que o projeto em questão está relacionado com um &lt;em&gt;App&lt;/em&gt; bastante famoso no Brasil, a Carteira Digital de Trânsito — &lt;em&gt;App&lt;/em&gt; desenvolvido pelo &lt;a href="https://www.serpro.gov.br" rel="noopener noreferrer"&gt;SERPRO&lt;/a&gt; e disponível para &lt;a href="https://play.google.com/store/apps/details?id=br.gov.serpro.cnhe" rel="noopener noreferrer"&gt;Android&lt;/a&gt; e &lt;a href="https://apps.apple.com/br/app/carteira-digital-de-tr%C3%A2nsito/id1275057217" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;. Imaginava que isso poderia aumentar as chances de a palestra ser aceita.&lt;/p&gt;

&lt;p&gt;A descrição completa que enviei foi:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Durante o desenvolvimento da &lt;em&gt;Carteira Digital de Trânsito&lt;/em&gt;, percebi como era desafiador dar suporte a um &lt;em&gt;App&lt;/em&gt; com milhões de usuários integrado a diversos sistemas. Sonhei em criar uma interface interna simples e amigável para consultas que facilitassem o atendimento. Assim surgiu o &lt;strong&gt;Apoio CDT&lt;/strong&gt;, um sistema web que automatizou processos e permitiu consultas rápidas e seguras. Com &lt;em&gt;backend&lt;/em&gt; em Clojure e &lt;em&gt;front-end&lt;/em&gt; em Elm, desenvolvemos um MVP em três semanas. O resultado foi uma arquitetura web simples, eficiente e fácil de manter ao longo dos anos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Até onde sei, este foi o primeiro projeto da empresa que utilizada Clojure e também o primeiro a utilizar Elm. E esta foi a primeira vez que tive oportunidade de falar sobres este sistema para pessoas de fora da empresa onde trabalho!&lt;/p&gt;

&lt;h2&gt;
  
  
  Demais palestras e &lt;em&gt;workshops&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;O evento durou dois dias, sendo que no primeiro ocorreram os 2 &lt;em&gt;workshops&lt;/em&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Workshop&lt;/em&gt; de Clojure
&lt;/h3&gt;

&lt;p&gt;Um curso de introdução ao Clojure, em inglês, ministrado pelo &lt;a href="https://www.linkedin.com/in/christoph-neumann-6089438/" rel="noopener noreferrer"&gt;Christoph Neumann&lt;/a&gt;, &lt;em&gt;Developer Advocate&lt;/em&gt; de Clojure no Nubank.&lt;/p&gt;

&lt;p&gt;Embora eu já tenha experiência com Clojure (e inclusive seja instrutor do curso &lt;a href="https://www.udemy.com/course/clojure-introducao-a-programacao-funcional/" rel="noopener noreferrer"&gt;Clojure: Introdução à Programação Funcional&lt;/a&gt;), foi muito legal reforçar os principais conceitos desta linguagem e também aprendi alguns fundamentos que ainda não conhecia!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Workshop&lt;/em&gt; de Datomic
&lt;/h3&gt;

&lt;p&gt;O período da tarde do primeiro dia foi destinado ao &lt;em&gt;workshow&lt;/em&gt; do banco de dados &lt;a href="https://www.datomic.com" rel="noopener noreferrer"&gt;Datomic&lt;/a&gt;. Este foi ministrado em português pela &lt;a href="https://www.linkedin.com/in/aanacarolina/" rel="noopener noreferrer"&gt;Carolina Silva&lt;/a&gt; (a mesma que citei no começo deste artigo) e &lt;a href="https://www.linkedin.com/in/hanna-f-mariano-59578596/" rel="noopener noreferrer"&gt;Hanna Figueiredo&lt;/a&gt;, ambas &lt;em&gt;Software Engineering&lt;/em&gt; no Nubank.&lt;/p&gt;

&lt;p&gt;Eu já havia assistido várias palestras sobre o Datomic e sempre achei um banco de dados muito intrigante e interessante. Acredito que faria muito sentido utilizá-lo em vários dos projetos que atuo ou já atuei no passado.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;workshop&lt;/em&gt; mostrou vários conceitos teóricos do Datomic, mas também foi muito prático.&lt;/p&gt;

&lt;p&gt;Você pode conferir a parte prática do &lt;em&gt;workshop&lt;/em&gt; &lt;a href="https://github.com/Datomic/day-of-datomic-conj" rel="noopener noreferrer"&gt;neste repositório do GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Confesso que foi muitas informações em pouco tempo. Definitivamente, vou precisar voltar ao repositório e praticar bastante ainda para internalizar os principais conceitos deste banco de dados. Mas valeu muito a pena!&lt;/p&gt;

&lt;p&gt;Se antes eu achava que valeria a pena estudar este banco, agora tenho certeza!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conversas e &lt;em&gt;feedbacks&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Logo ao chegar no evento tive a oportunidade de conversar com algumas pessoas que só conhecia virtualmente, como o &lt;a href="https://www.linkedin.com/in/arthur-fucher/" rel="noopener noreferrer"&gt;Arthur Fücher&lt;/a&gt;. Além de ser &lt;em&gt;Senior Software Engineer&lt;/em&gt; no Nubank, Arthur é uma figura muito presente na comunidade Clojure do Brasil!&lt;/p&gt;

&lt;p&gt;E mesmo sendo uma pessoa bastante tímida, foi possível conhecer muitas pessoas bacanas do Brasil e de outros países.&lt;/p&gt;

&lt;p&gt;Em especial, fui &lt;strong&gt;muito&lt;/strong&gt; bem recebido pelo Christoph Neumann. Eu estava parado em um canto no &lt;em&gt;happy hour&lt;/em&gt;, após o segundo dia de evento, comendo e pensando em já ir pra casa, quando ele se aproximou e puxou conversa. Conversamos um pouco e comecei a fazer algumas perguntas sobre Datomic. Ao longo da conversa, citei que talvez fosse um banco de dados interessante para empresa onde trabalho. Quando falei onde trabalhava e o que a empresa fazia, ele se mostrou bastante interessado! E logo se ofereceu para me apresentar o &lt;a href="https://www.linkedin.com/in/joe-lane-7674173a/" rel="noopener noreferrer"&gt;Joe Lane&lt;/a&gt;, &lt;em&gt;Principal Engineer Building Datomic&lt;/em&gt; na Nubank!&lt;/p&gt;

&lt;p&gt;Conversei com o Joe e, mais uma vez, fui super bem recebido! Ele mostrou bastante entusiasmo quando comentei onde trabalhava e os tipos de projetos que o SERPRO desenvolve, e ficou à disposição para tirar dúvidas sobre Datomic, inclusive comentando que o SERPRO poderia ser um ótimo &lt;em&gt;case&lt;/em&gt; para o Datomic.&lt;/p&gt;

&lt;p&gt;Ao longo do evento também tive a oportunidade de conhecer algumas pessoas que fizeram &lt;a href="https://www.udemy.com/course/clojure-introducao-a-programacao-funcional/" rel="noopener noreferrer"&gt;meu curso de Clojure&lt;/a&gt;! Entre essas pessoas, conheci o &lt;a href="https://www.linkedin.com/in/bruno-dobelin/" rel="noopener noreferrer"&gt;Bruno Guimarães&lt;/a&gt;, que atualmente é &lt;em&gt;Senior Software Engineer&lt;/em&gt; no Nubank e foi &lt;em&gt;host&lt;/em&gt; da conferência.&lt;/p&gt;

&lt;p&gt;Conhecer pessoalmente pessoas que fizeram meu curso online é sempre uma experiência muito legal! Os números, as estatísticas, os comentários, ganham um cara, uma voz, vida. É sempre muito gratificante!&lt;/p&gt;

&lt;p&gt;No segundo dia, após a minha apresentação, muitas pessoas vieram conversar e querer saber mais sobre como consegui introduzir Clojure em um sistema do governo federal brasileiro. Tiveram algumas dúvidas mais pontuais, sobre minha motivação para usar &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; no &lt;em&gt;front-end&lt;/em&gt; (e não optar por utilizar Clojure em sua versão &lt;a href="https://clojurescript.org" rel="noopener noreferrer"&gt;ClojureScript&lt;/a&gt;), entre várias outras conversas interessantes.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;feedback&lt;/em&gt; foi bastante positivo e todas as conversas foram muito bacanas, bem humoradas e respeitosas. &lt;/p&gt;

&lt;h2&gt;
  
  
  Comidas (e mais conversas)
&lt;/h2&gt;

&lt;p&gt;O evento contava com &lt;em&gt;welcome coffee&lt;/em&gt; no início do dia e &lt;em&gt;coffee breaks&lt;/em&gt; ao longo do dia. A qualidade era muito boa e tudo muito formal (talvez formal até um pouco demais? rs).&lt;/p&gt;

&lt;p&gt;Já para almoçar, existiam várias opções (não inclusas no valor do ingresso) de restaurantes dentro do mesmo complexo de prédios onde encontra-se a &lt;a href="https://building.nubank.com/pt-br/escritorio-nubank-brasil-spark/" rel="noopener noreferrer"&gt;Nubank Sparks&lt;/a&gt;. Isso facilitava bastante, já que não precisava sair do local, especialmente no primeiro dia, de workshops, já que estava com meu notebook.&lt;/p&gt;

&lt;p&gt;Você pode almoçar onde quiser. Mas gostei das opções que estavam disponíveis ali perto e foi mais uma oportunidade de conversar com mais pessoas do evento. Novamente, mesmo sendo bastante tímido e sentando em um lugar mais afastado, logo vieram várias pessoas sentar junto comigo e puxar conversa. Neste momento conheci uma Ucraniana que mostrou pra gente o App &lt;em&gt;Diia&lt;/em&gt;, onde ela pode ter versões digitais de vários de seus documentos, como Carteira de Motorista, Passaporte, entre outros e ter acesso a mais de 130 serviços do governo Ucraniano (você pode saber mais sobre este App &lt;a href="https://en.wikipedia.org/wiki/Diia" rel="noopener noreferrer"&gt;nesta página do Wikipedia&lt;/a&gt;)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Valeu a pena?
&lt;/h2&gt;

&lt;p&gt;Definitivamente, sim!&lt;/p&gt;

&lt;p&gt;O evento ocorreu em dois dias da semana (uma segunda e terça-feira). Isso talvez atrapalhe a participação de algumas pessoas — um colega meu não conseguiu participar pois a empresa não liberou este dias para ele, por exemplo. Mas para aquelas pessoas que conseguem participar, fica muito menos cansativo do que ter um evento como este no final de semana, depois de uma longa semana de trabalho.&lt;/p&gt;

&lt;p&gt;Eu havia comprado os ingressos na pré-venda, antes de ter minha palestra aprovada, mas depois tive o valor estornado pela coordenação do evento - ganhei ingressos para os dois dias por ser palestrante. Também me ofereceram ajuda para transporte e estadia, a qual eu recusei, já que o evento seria próximo da minha residência.&lt;/p&gt;

&lt;p&gt;A experiência de palestrar em um evento desta magnitude, mesmo que por apenas 10 minutos, foi incrível! É uma sensação de muita gratidão às pessoas que ajudaram a organizar a conferência e que confiaram no meu potencial!&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>programaçãofuncional</category>
      <category>nubank</category>
      <category>serpro</category>
    </item>
    <item>
      <title>How was my experience at Lambda Days 2025</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Fri, 14 Nov 2025 17:49:51 +0000</pubDate>
      <link>https://dev.to/marciofrayze/how-was-my-experience-at-lambda-days-2025-2kc2</link>
      <guid>https://dev.to/marciofrayze/how-was-my-experience-at-lambda-days-2025-2kc2</guid>
      <description>&lt;p&gt;A Brazilian Portuguese version of this article is available &lt;a href="https://dev.to/marciofrayze/como-foi-minha-experiencia-na-lambda-days-2025-27k3"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Lambda Days?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.lambdadays.org" rel="noopener noreferrer"&gt;Lambda Days&lt;/a&gt; is an international conference dedicated to functional programming languages held every year in Kraków (Poland). The event brings together researchers, developers, and enthusiasts from communities such as Erlang, Elixir, Scala, F#, Clojure, Haskell, Elm, and many others, creating a space for exchange between academia and industry, and lasts for 2 days.&lt;/p&gt;

&lt;p&gt;In addition to technical talks, Lambda Days also covers topics such as data science, distributed systems, artificial intelligence, and good development practices. The atmosphere is very vibrant, bringing together participants from different countries in one of the most beautiful and historic cities in Europe.&lt;/p&gt;

&lt;h2&gt;
  
  
  What motivated me to go this year?
&lt;/h2&gt;

&lt;p&gt;I had 10 days of vacation to take and no certain destination to go. All the places I thought about visiting seemed to have great potential for a nice trip, but indecision took over. Until I remembered the feeling I had when I saw that &lt;a href="https://www.lambdadays.org/lambdadays2025/evan-czaplicki" rel="noopener noreferrer"&gt;Evan Czaplicki&lt;/a&gt; was going to give a talk at this conference!&lt;/p&gt;

&lt;p&gt;For those who don’t know him, Evan is the creator of the &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; programming language and probably my favorite speaker! I am a great admirer of his technical abilities, but I am also equally impressed by the philosophical ideas he often includes in his speeches.&lt;/p&gt;

&lt;p&gt;I had always wanted to attend a talk by Evan in person, and in recent years he hasn’t made many public appearances, being more focused on developing his newest creation: &lt;a href="https://acadia.engineering" rel="noopener noreferrer"&gt;Acadia&lt;/a&gt;. That’s why, when I saw that he would be there, I got very excited.&lt;/p&gt;

&lt;p&gt;Another key factor in my decision was that, although Poland was not exactly among the top places I wanted to visit in the world, it seemed to be a very interesting and beautiful country, with very distinct cultural, gastronomic, and tourist options. And it is also not one of the most expensive European countries to visit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the city like?
&lt;/h2&gt;

&lt;p&gt;Lambda Days takes place every year in the same city, Kraków. I liked the choice for several reasons. The first, as I already mentioned, is the cost. Although Poland has been a member of the European Union since 2004, it has never adopted the Euro, and its official currency is the złoty (PLN). This can make some things slightly inconvenient, but I found everything quite affordable, especially when compared to richer European countries. The price of the hotel, food, public transportation, and day-to-day expenses were not much higher than what I would find on a trip within Brazil.&lt;/p&gt;

&lt;p&gt;The flight, departing from Brazil, is also not excessively expensive, especially considering it’s an 11-hour trip to Frankfurt and then another hour to Kraków (I prefer not to include how much I paid because the price would become outdated too quickly).&lt;/p&gt;

&lt;p&gt;Kraków is a beautiful city! And since the event takes place in the summer, the sun rises very early and sets very late (photo taken at 9:45 PM).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1ed6hiremgmbw6814qd.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1ed6hiremgmbw6814qd.jpeg" alt="Photo of the city at night, with the sky still bright." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I felt very safe the whole time. Since the city is very flat, it’s perfect for walking or cycling. And, of course, there are countless trams that run throughout the entire city! Through an App on your phone (or a machine at the stops) you can buy your ticket. I opted to use an App and buy a time-based ticket. This way, I could move around the city without worrying. You just validate it once (by typing the tram car number, which is printed inside near the doors) and that’s it! They say there is strict ticket inspection (in that case, you just show the validation on the App, otherwise you’ll be fined!), but in practice, I didn’t see any checks. I also found the price very reasonable (especially compared to what I paid in Norway… I almost fell backwards when I saw the public transport prices in Oslo!).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmqtxihl9n792gjv45w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmqtxihl9n792gjv45w6.png" alt="Tram" width="406" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apparently, it’s quite easy to get from the airport to the city using regular trains. But I chose to use Uber. I was super tired from the trip and felt safer choosing this option.&lt;/p&gt;

&lt;p&gt;Another highlight is that Kraków has some very unique tourist attractions. When I travel, I usually prefer walking around the city instead of doing very touristy tours. But this time I decided to visit Auschwitz I and Auschwitz II (Birkenau). It’s hard to describe the feeling of being in a place where literally thousands of people (mostly Jews) died. I still haven’t fully processed it. It’s not the kind of place everyone will want to visit, but if you’re interested and emotionally prepared, I’d recommend going.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fls3h6k9tyvh8m64p1wc2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fls3h6k9tyvh8m64p1wc2.jpeg" alt="Foto de dentro de Auschwitz." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also visited the famous Wieliczka Salt Mine. It’s a beautiful place, but it probably would have been more interesting to visit other parts of the city, such as a forest park a bit farther away.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feueual0rd5l3f6y1mtqc.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feueual0rd5l3f6y1mtqc.jpeg" alt="Inside the mine." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another very famous place (and one I regret not visiting) is Schindler’s Factory, which shows the efforts Schindler made to save 1,200 Jews from the Holocaust (those who watched &lt;em&gt;Schindler’s List&lt;/em&gt; may know part of this story).&lt;/p&gt;

&lt;p&gt;I chose to stay only in Kraków, but it seems quite easy to travel to other Polish cities by train. If I could go back in time, I would’ve planned the trip better and spent a few days in Warsaw, the country’s capital.&lt;/p&gt;

&lt;p&gt;The only thing I really disliked about the city was the invasion of “vapes” (electronic cigarettes). Although it’s relatively common to see people using these devices here in Brazil (even though they’re prohibited), in Kraków it seemed like every young adult on the street was carrying one. A real epidemic! And they were sold in many places across the city. It’s a sad sight, considering the well-known health issues associated with these products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level of the talks
&lt;/h2&gt;

&lt;p&gt;There were 3 tracks, with talks happening in parallel. Some were very easy to follow, such as the discussion panel &lt;em&gt;Learning How to Learn&lt;/em&gt;, where four women (including a Brazilian!) shared their journeys learning, teaching, and growing in their Functional Programming careers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7dbxw3fro6jj8421w81.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7dbxw3fro6jj8421w81.jpeg" alt="Four women talking." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other talks were more philosophical, such as Evan Czaplicki’s keynote, titled &lt;em&gt;Rethinking our Adoption Strategy&lt;/em&gt;. In it, he talked about what he calls a &lt;em&gt;Platform Language&lt;/em&gt; and what differentiates it from a &lt;em&gt;Productivity Language&lt;/em&gt;, and what we — people not directly related to the business world — could do to make &lt;em&gt;Platform Languages&lt;/em&gt; more appealing than &lt;em&gt;Productivity Languages&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyihjst2rkl20ud7izmm5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyihjst2rkl20ud7izmm5.jpeg" alt="Evan's talk." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There were also more abstract talks, such as Moa Johansson’s keynote: &lt;em&gt;AI for Mathematical Discovery: Symbolic, Neural and Neuro-Symbolic Methods&lt;/em&gt;. I must confess, the level of this (and some others) was far above what I could follow. I still managed to learn some things, but a lot of it I couldn’t fully understand. Another example was the keynote by Martin Odersky, creator of the Scala programming language, titled &lt;em&gt;Making Capabilities Safe and Convenient&lt;/em&gt;. I understood the basics, but after a certain point, I got lost and couldn’t follow the proposals anymore.  &lt;/p&gt;

&lt;p&gt;Since there were 3 rooms/tracks happening concurrently, you can choose whichever talks seem most interesting and useful to you (except keynotes — those happen in the main room with no parallel sessions). A mistake I made was not researching the speakers beforehand. I could’ve made better choices and enjoyed more of the content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good food!
&lt;/h2&gt;

&lt;p&gt;The event included breakfast, two coffee breaks (morning and afternoon), and lunch. That was great because I didn't have to worry about meals, and it also gave everyone more opportunities to socialize, chat, and make (or strengthen) friendships. I found everything very organized and tasty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Party / Happy hour
&lt;/h2&gt;

&lt;p&gt;At the end of the first day, there was a gathering after the event, at another venue. To enter, you just needed to show your event badge.&lt;/p&gt;

&lt;p&gt;I don’t have many details about how it went, because unfortunately I didn’t attend. I was very tired after a long day of talks and went back to my hotel. But I regret not taking the opportunity! I was especially regretful when I heard, from some Brazilian attendees I met, that José Valim (creator of Elixir) was at the party! And they were able to talk to him! He didn’t give a talk at the event and I didn’t see him at any point, so I was surprised to learn he was there (and I missed the chance to meet him…).&lt;/p&gt;

&lt;h2&gt;
  
  
  First trip with so much technology at my disposal
&lt;/h2&gt;

&lt;p&gt;I’ve had the privilege of taking several international trips over the past decades, from Argentina, Chile, and Uruguay, to Norway, Sweden, and the Netherlands, to Costa Rica, the United States, Cuba… but this trip to Poland was different.&lt;/p&gt;

&lt;p&gt;When I visited Cuba in 2009, making a phone call to Brazil was very expensive and restricted (I made a few calls from the hotel’s landline). Zero internet or cell phone access. On my trip to the Netherlands in 2012, I only had internet when I found Wi-Fi (using my iPhone 3GS!). Most of the time I navigated the city using a physical map — no GPS.&lt;/p&gt;

&lt;p&gt;On this trip to Poland, for the first time I had several technologies available that made my stay MUCH easier!&lt;/p&gt;

&lt;h3&gt;
  
  
  Unlimited internet
&lt;/h3&gt;

&lt;p&gt;Before traveling, I bought an eSIM (a virtual SIM card — still not very popular in Brazil) through the Holafly app. The process was super simple and in a short time I had a second SIM installed on an iPhone 14. As soon as the plane stopped for my layover in Germany, at Frankfurt International Airport, my chip started working and I already had unlimited internet! WhatsApp working normally and everything else I’m used to using in Brazil. For the first time, I arrived in another country already with internet active on my phone!&lt;/p&gt;

&lt;h3&gt;
  
  
  Uber
&lt;/h3&gt;

&lt;p&gt;Uber also operates in Poland and I felt safer and more comfortable using the service to get to my hotel. Poland’s train network is very good and I’m sure I could’ve arrived using trains alone, since the hotel was near a station — something I should’ve checked before getting there, but I didn’t! Poor planning there. In any case, the Uber dropped me off right at the hotel door. It was the first time I didn’t have to worry about anything to arrive safely at my first stop on an international trip.&lt;/p&gt;

&lt;p&gt;I also used Uber to return to the airport. The rest of the time, I used only public transportation. But knowing that I had that option at any time made me feel more at ease to explore the city freely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Maps / GPS
&lt;/h3&gt;

&lt;p&gt;Google Maps works &lt;strong&gt;extremely&lt;/strong&gt; well in Kraków and helped me a lot getting around the city using trams. It told me exactly when the tram would arrive at the stop, showed me how many stops were left, and alerted me at the correct moment to get off. It had never been so easy to use public transport in an unfamiliar city!  &lt;/p&gt;

&lt;p&gt;Of course, even so, I got lost a few times haha. In the rush, I would hop on a tram going in the wrong direction. But it was easy to notice by looking at the map, and since I bought time-based tickets, I just got off and took the correct tram.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chat GPT
&lt;/h3&gt;

&lt;p&gt;Another novelty was traveling for the first time with the possibility of using more recent Generative AI technologies like Chat GPT. I asked questions throughout the trip to understand how things worked in the city, and it helped me find stores and some nice places to visit.&lt;/p&gt;

&lt;p&gt;Something I tried a few times was taking a screenshot of Google Maps with my current location and sending it to Chat GPT, asking for tips on things to visit nearby or stores where I could buy certain items I was looking for. The result was very cool!&lt;br&gt;&lt;br&gt;
If it weren’t for Chat GPT, I wouldn’t have visited, for example, the Kościuszko Mound. I was right next to it but it wasn’t on my list of places to visit. I followed the process I mentioned above, and it recommended going there — and I really liked it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Opportunities for incredible conversations
&lt;/h2&gt;

&lt;p&gt;As I said in the beginning, my biggest motivation for going to this event was to attend Evan Czaplicki’s talk and, of course, I had expectations that he would talk a bit about his new project, which very few people have had access to. When I saw the title of the talk, I already imagined this wouldn’t be the focus — and indeed it wasn’t. But what about behind the scenes?&lt;/p&gt;

&lt;p&gt;During the two days of the event, he was talking with attendees in the hall where the coffee break took place. On the first day I tried to approach him to ask some questions, but my shyness won and I went back to the hotel feeling defeated! There, I told myself: you came all the way here because of this! If he’s there tomorrow, you &lt;em&gt;will&lt;/em&gt; talk to him!!&lt;/p&gt;

&lt;p&gt;And to my surprise, the next day he was there again, talking to people. Once again I felt embarrassed, but gathered the courage and approached. I didn’t know how to start, so I just greeted him and the person he was talking with using a nod and waited my turn while, for some reason, they were discussing Japanese culture.&lt;/p&gt;

&lt;p&gt;At some point, he turned to me and gestured to start a conversation. I introduced myself, thanked him for the talk, praised his work as a programmer but also as a speaker and philosopher, and told him I was very inspired by his talks. We exchanged a few words and I soon asked about his “secret” backend project. I asked some general question about what it was about, and he paused for a few seconds. I got worried, honestly. Would he give a dry response? Was I being too invasive? Who was I to ask about a project he clearly doesn’t want to share widely yet??&lt;/p&gt;

&lt;p&gt;But after a few seconds, he said: do you want to see it? I have my development notebook here — if you have a few minutes, I can give you a demo.&lt;/p&gt;

&lt;p&gt;I accepted immediately! He asked me to wait a moment so he could call two more people who were interested in seeing the demo. Soon the four of us gathered around a high table in the hall, where he opened his notebook and began presenting the project. After some time, the other two had to leave, and I was also leaving with them when he said: I have one more demo, don’t you want to see it? And once again, I enthusiastically said yes!&lt;/p&gt;

&lt;p&gt;At that moment, he presented the demo only to me. I asked a few questions and after 40 minutes of conversation, I thanked him and said goodbye. Then he asked for my opinion about the product, whether I would use it. And he also asked for my opinion about the demo — whether it was good, and if the proposal of the project was clear.&lt;/p&gt;

&lt;p&gt;There I was, in Poland, giving my personal feedback to one of my idols! What an indescribable experience!! Those 40 minutes alone made the whole trip to Poland worthwhile!&lt;/p&gt;

&lt;h2&gt;
  
  
  Was it worth it?
&lt;/h2&gt;

&lt;p&gt;As you can imagine — yes, it was totally worth it!&lt;/p&gt;

&lt;p&gt;Overall, it wasn’t a cheap trip. Far from it! There were the flight, accommodation, the event ticket… all paid with my own money, without any company support. Because of that, it’s hard to recommend a trip like this without some hesitation.&lt;/p&gt;

&lt;p&gt;I loved it. I had fun, I learned, I discovered a new country, I made new friends… And maybe you will meet incredible people and get the job of your dreams? Maybe. But probably not. If that’s your only goal, I recommend searching online instead — in communities, social networks, writing articles or software…&lt;/p&gt;

&lt;p&gt;So if you’re thinking about doing something similar, do it for pleasure. For fun. Only then is it truly worth it!&lt;/p&gt;




&lt;p&gt;Did you like this article? &lt;strong&gt;Don't forget to leave a reaction!&lt;/strong&gt; They serve as a big incentive for me to write others.&lt;/p&gt;

&lt;p&gt;You can also discover more articles, podcasts and videos at: &lt;a href="https://segunda.tech/tags/english" rel="noopener noreferrer"&gt;https://segunda.tech/tags/english&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want, follow me on &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="https://staging.bsky.app/profile/segunda.tech" rel="noopener noreferrer"&gt;blue sky&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/marcio-frayze" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>lambdadays</category>
      <category>functional</category>
      <category>elm</category>
      <category>elixir</category>
    </item>
    <item>
      <title>Como foi minha experiência na Lambda Days 2025</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Mon, 10 Nov 2025 23:56:51 +0000</pubDate>
      <link>https://dev.to/marciofrayze/como-foi-minha-experiencia-na-lambda-days-2025-27k3</link>
      <guid>https://dev.to/marciofrayze/como-foi-minha-experiencia-na-lambda-days-2025-27k3</guid>
      <description>&lt;h2&gt;
  
  
  O que é a Lambda Days?
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://www.lambdadays.org" rel="noopener noreferrer"&gt;Lambda Days&lt;/a&gt; é uma conferência internacional dedicada a linguagens funcionais realizada todos os anos na Cracóvia (Polônia). O evento reúne pesquisadores, pessoas desenvolvedoras e entusiastas de comunidades como Erlang, Elixir, Scala, F#, Clojure, Haskell, Elm e muitas outras, criando um espaço de troca entre a academia e a indústria e tem duração de 2 dias.&lt;/p&gt;

&lt;p&gt;Além das palestras técnicas, a Lambda Days também aborda temas como ciência de dados, sistemas distribuídos, inteligência artificial e boas práticas de desenvolvimento. O ambiente é bastante vibrante, reunindo participantes de diferentes países em uma das cidades mais bonitas e históricas da Europa.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que me motivou a ir este ano?
&lt;/h2&gt;

&lt;p&gt;Eu tinha 10 dias de férias para tirar e nenhum destino certo para ir. Todos os lugares que pensava em visitar pareciam ter muito potencial para uma viagem bacana, mas a indecisão tomava conta. Até que lembrei da sensação que tive quando vi que o &lt;a href="https://www.lambdadays.org/lambdadays2025/evan-czaplicki" rel="noopener noreferrer"&gt;Evan Czaplicki&lt;/a&gt; iria fazer uma apresentação nesta conferência!   Para quem não o conhece, Evan é criador da linguagem &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; e provavelmente o meu palestrante favorito! Sou grande admirador das suas capacidades técnicas, mas também fico igualmente impressionado e atento às ideias mais filosóficas que ele costuma incluir em seus discursos.&lt;/p&gt;

&lt;p&gt;Sempre quis assistir uma palestra do Evan pessoalmente e nos últimos anos ele não tem feito muitas aparições públicas, estando mais focado no desenvolvimento da sua mais nova criação: &lt;a href="https://acadia.engineering" rel="noopener noreferrer"&gt;Acadia&lt;/a&gt;. Por isso, quando vi que ele estaria lá, fiquei bem empolgado.&lt;/p&gt;

&lt;p&gt;Outro ponto importante na decisão foi que, embora a Polônia não estivesse exatamente entre meus lugares prioritários para conhecer no mundo, me parecia ser um país bem interessante, bonito e com opções culturais, gastronômicas e turísticas muito distintas. Além de não ser um dos países europeus dos mais caros de se visitar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como é a cidade?
&lt;/h2&gt;

&lt;p&gt;A Lambda Days ocorre todo ano na mesma cidade, Cracóvia. Eu gostei da escolha por várias razões. A primeira, como já mencionei, é econômica. Embora a Polônia seja membro da União Europeia desde 2004, ela nunca adotou o Euro e sua moeda oficial é a złoty (PLN). Isso pode dificultar algumas coisas, mas considerei o preço de tudo bastante convidativo, especialmente quando comparado com outros países mais ricos da Europa. O preço do hotel, comida, transporte público e dos gastos gerais do dia a dia não são muito acima dos preços que eu encontraria em uma viagem dentro do próprio Brasil.&lt;/p&gt;

&lt;p&gt;A passagem, saindo do Brasil, também não é um preço exorbitante, especialmente se considerarmos que trata-se de uma viagem de 11 horas até Frankfurt e depois mais uma hora até Cracóvia (prefiro não colocar os valores de quanto paguei pois iria se desatualizar muito rapidamente).&lt;/p&gt;

&lt;p&gt;Cracóvia é uma cidade linda! E como o evento ocorre no verão, o sol nasce super cedo e se põe bem à noite (foto tirada às 21:45h).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1ed6hiremgmbw6814qd.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1ed6hiremgmbw6814qd.jpeg" alt="Foto da cidade à noite, com céu ainda claro." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Me senti bastante seguro o tempo todo. Como a cidade é super plana, é perfeita para andar à pé ou de bicicleta. Além, claro, dos inúmeros trens de superfície (vulgo bondinhos) que percorrem a cidade toda! Através de um &lt;em&gt;App&lt;/em&gt; no celular (ou de uma maquininha nos próprios pontos de parada) você pode comprar sua passagem. Eu acabei optando por usar um &lt;em&gt;App&lt;/em&gt; e comprar passagem por tempo de uso. Assim, conseguia andar a cidade toda sem precisar me preocupar. Basta validar uma vez (digitando o número do vagão, que está impresso na parte de dentro, próximo das portas) e pronto! Dizem que existe bastante fiscalização (neste caso, basta mostrar que você validou sua passagem no &lt;em&gt;App&lt;/em&gt;, caso contrário você será multado!), mas na prática não vi nenhum controle sobre isso. O preço também achei bastante aceitável (principalmente se comparado com que eu tinha que pagar quando visitei a Noruega… quase caí pra trás ao ver os preços do transporte público quando estive em Oslo!).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmqtxihl9n792gjv45w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmqtxihl9n792gjv45w6.png" alt="Trem de superfície (bondinho)" width="406" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aparentemente é bastante tranquilo chegar do aeroporto para a cidade usando trens (não os bondinhos - trens mesmo). Mas eu optei para usar Uber. Estava super cansado da viagem e me senti mais seguro optando por este meio de transporte.&lt;/p&gt;

&lt;p&gt;Outro ponto de destaque é que Cracóvia possui algumas opções turísticas bastante únicas. Quando viajo, costumo optar mais por andar pela cidade e evitar um pouco passeios muito turísticos. Mas desta vez decidi conhecer Auschwitz 1 e Auschwitz 2 (Birkenau). É difícil descrever a sensação de estar em um lugar onde literalmente milhares de pessoas (em sua maioria judeus) morreram. Até agora não consigo acreditar. Não é o tipo de lugar que todas as pessoas vão querer visitar, mas se você tiver interesse e disposição, eu recomendaria conhecer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fls3h6k9tyvh8m64p1wc2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fls3h6k9tyvh8m64p1wc2.jpeg" alt="Foto de dentro de Auschwitz." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Também fui na famosa Mina de Sal de Wieliczka. É um lugar bem bonito, mas provavelmente teria sido mais interessante ter ido para outras partes da cidade, como algum parque florestal mais afastado. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feueual0rd5l3f6y1mtqc.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feueual0rd5l3f6y1mtqc.jpeg" alt="Foto de dentro da mina de sal." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outro ponto bastante famoso (e que me arrependo de não ter visitado) é a Fábrica de Schindler, que mostra o esforço feito por Schindler para salvar 1.200 judeus do Holocausto (quem assistiu o filme &lt;em&gt;A Lista de Schindler&lt;/em&gt; deve conhecer um pouco desta história).&lt;/p&gt;

&lt;p&gt;Optei por ficar apenas na Cracóvia, mas parece ser bastante fácil ir para outras cidades da Polônia de trem. Se pudesse voltar no tempo, organizaria um pouco melhor minha viagem e passaria alguns dias em Varsóvia, capital do país.&lt;/p&gt;

&lt;p&gt;A única coisa que eu realmente não gostei na cidade foi a invasão dos “vapes” (cigarro eletrônico). Embora seja relativamente comum ver pessoal no Brasil com estes dispositivos (mesmo sendo proibido), na Cracóvia parecia que todo jovem adulto que estava na rua carregava um “vape” na mão. Uma verdadeira epidemia! E o mesmo era vendido em vários lugares da cidade. É uma cena um pouco triste, já que os problemas associados ao consumo deste tipo de produto já são bastante conhecidos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nível das palestras
&lt;/h2&gt;

&lt;p&gt;Haviam 3 trilhas, com palestras acontecendo paralelamente. Algumas eram bem tranquilas de acompanhar, como o painel de discussão &lt;em&gt;Learning How to Learn&lt;/em&gt;, onde quatro mulheres (incluindo uma brasileira!) contavam um pouco sobre a sua jornada para aprender, ensinar e crescer em suas carreiras em Programação Funcional.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7dbxw3fro6jj8421w81.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7dbxw3fro6jj8421w81.jpeg" alt="Foto de 4 mulheres conversando." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outras palestras eram mais filosóficas, como a &lt;em&gt;keynote&lt;/em&gt; realizada pelo Evan Czaplicki, intitulada &lt;em&gt;Rethinking our Adoption Strategy&lt;/em&gt;. Nesta, ele falou sobre o que ele chama de &lt;em&gt;Platform Language&lt;/em&gt; e o que a diferencia de uma &lt;em&gt;Productivity Language&lt;/em&gt; e o que nós, pessoas não relacionadas ao mundo dos negócios, poderíamos fazer para tornar as &lt;em&gt;Platform Languages&lt;/em&gt; mais atrativas que as &lt;em&gt;Productivity Languages&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyihjst2rkl20ud7izmm5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyihjst2rkl20ud7izmm5.jpeg" alt="Foto do Evan palestrando." width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Haviam ainda palestras em níveis mais abstratos, como o &lt;em&gt;keynote&lt;/em&gt; de Moa Johansson: &lt;em&gt;AI for Mathematical Discovery: Symbolic, Neural and Neuro-Symbolic Methods&lt;/em&gt;. Confesso que o nível desta (e de algumas outras palestras) estavam muito acima do que eu conseguia acompanhar. Sempre era possível tirar algum conhecimento novo, mas muita coisa eu não tinha capacidade de compreender totalmente. Outro exemplo foi a &lt;em&gt;keynote&lt;/em&gt; do Martin Odersky, criador da linguagem de programação Scala, com o título &lt;em&gt;Making Capabilities Safe and Convenient&lt;/em&gt;. Consegui entender os fundamentos, mas a partir de um determinado momento da palestra, me perdi e não conseguia mais acompanhar as propostas.  &lt;/p&gt;

&lt;p&gt;Como eram 3 salas/trilhas com palestras acontecendo de forma concorrente, você tem a opção de escolher aquelas que julgar mais interessantes e que vai tirar mais proveito (menos às &lt;em&gt;keynotes&lt;/em&gt; - essas ocorrem na sala maior e sem outras palestras no mesmo momento). Um erro que cometi foi não ter estudado melhor sobre as pessoas que iriam palestrar. Poderia ter feito escolhas mais interessantes e ter aproveitado mais conteúdos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comida boa!
&lt;/h2&gt;

&lt;p&gt;  Estava incluso no evento o café da manhã, dois &lt;em&gt;coffe-breaks&lt;/em&gt; (pela manhã e tarde) e um almoço. Isso é bem legal pois não precisava me preocupar com alimentação e também era um momento a mais que o pessoal utilizava para socializar, conversar e fazer (ou fortalecer) amizades. Achei tudo bastante organizado e gostoso.&lt;/p&gt;

&lt;h2&gt;
  
  
    Festa / &lt;em&gt;Happy hour&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;No final do primeiro dia ocorreu uma confraternização após o evento, em outro local. Para entrar bastava mostrar a credencial do evento.&lt;/p&gt;

&lt;p&gt;Não tenho muitos detalhes de como foi, pois infelizmente eu não participei. Estava bastante cansado depois de um longo dia de palestras e acabei voltando para meu hotel. Mas me arrependo de não ter aproveitado esta oportunidade! Fiquei especialmente arrependido quando soube, através de algumas pessoas brasileiras que conheci no evento, que o José Valim (criador da linguagem Elixir) estava presente na festa! E que conseguiram conversar com ele! Ele não palestrou no evento e não o vi em nenhum momento, então fiquei surpreso ao saber que ele estava lá (e eu perdi a oportunidade de conhecê-lo…).&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeira viagem com tanta tecnologia à minha disposição
&lt;/h2&gt;

&lt;p&gt;Tive o privilégio de fazer várias viagens internacionais nas últimas décadas, desde Argentina, Chile, Uruguai, até Noruega, Suécia, Holanda, passando por Costa Rica, Estados Unidos, Cuba, … mas esta viagem para Polônia foi diferente. &lt;/p&gt;

&lt;p&gt;Quando visitei Cuba, em 2009, fazer uma ligação telefônica para o Brasil era muito caro e restrito (fiz algumas vezes, de um telefone fixo do Hotel). Zero acesso à internet ou telefone celular. Em minha viagem para Holanda, em 2012, internet apenas quando conseguia uma wi-fi (usando meu iPhone 3GS!). A maior parte do tempo me locomovia olhando um mapa físico da cidade, nada de GPS.&lt;/p&gt;

&lt;p&gt;Nesta viagem para Polônia, pela primeira vez tinha a minha disposição diversas tecnologias que facilitaram MUITO a estadia por lá!&lt;/p&gt;

&lt;h3&gt;
  
  
  Internet ilimitada
&lt;/h3&gt;

&lt;p&gt;Antes de viajar eu já havia comprado um eSIM (um chip virtual de celular - coisa que ainda não é muito popular no Brasil) através do &lt;em&gt;App&lt;/em&gt; da Holafly. O processo foi super simples e em pouco tempo tinha um segundo chip instalado em um iPhone 14. Assim que o avião parou na escala que eu precisava fazer na Alemanha, no aeroporto Internacional de Frankfurt, meu chip já passou a funcionar e eu já tinha acesso ilimitado à internet! WhatsApp funcionando normalmente e tudo mais que eu já estava acostumado a usar no Brasil. Pela primeira vez cheguei em outro país já com internet disponível em meu celular!&lt;/p&gt;

&lt;h3&gt;
  
  
  Uber
&lt;/h3&gt;

&lt;p&gt;A Uber opera também na Polônia e me senti mais confortável e seguro utilizando o serviço deles para conseguir chegar em meu hotel. A rede de trens da Polônia é muito boa e com certeza eu conseguiria chegar usando apenas trens, já que o Hotel ficava perto de uma estação - coisa que eu deveria ter visto antes de chegar lá, mas não fiz! Meu planejamento deixou a desejar também neste ponto. De qualquer forma, o Uber me deixou na porta do hotel. Foi a primeira vez que não precisei me preocupar com nada para conseguir chegar tranquilo em meu primeiro destino em uma viagem internacional.&lt;/p&gt;

&lt;p&gt;Acabei optando por utilizar o Uber também para voltar para o aeroporto. De resto, usei apenas o transporte público. Mas saber que eu tinha esta opção a qualquer momento, me deixava mais tranquilo para explorar a cidade à vontade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Maps / GPS
&lt;/h3&gt;

&lt;p&gt;O Google Maps funciona &lt;strong&gt;muito&lt;/strong&gt; bem na Cracóvia e me ajudou demais a me locomover pela cidade usando os trens de superfície. Ele me avisava exatamente quando o trem iria chegar na estação, me mostrava quantas estações faltavam para descer e me alertava na hora exata de descer. Nunca foi tão fácil andar de transporte público em uma cidade desconhecida!   &lt;/p&gt;

&lt;p&gt;Claro que mesmo assim eu me perdi alguma vezes haha. Na pressa entrava no trem no sentido errado e coisas do tipo. Mas era fácil perceber o erro ao olhar o mapa e, como as passagens que eu comprava eram por tempo, bastava descer e pegar o trem correto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chat GPT
&lt;/h3&gt;

&lt;p&gt;Outra novidade foi viajar pela primeira vez com a possibilidade de usar tecnologias mais recentes de Inteligência Artificial Generativa, como o Chat GPT. Fazia algumas perguntas ao longo da viagem para tirar dúvidas sobre o funcionamento das coisas nesta cidade, ele me ajudou a encontrar lojas e também a encontrar alguns pontos bonitos para visitar. &lt;/p&gt;

&lt;p&gt;Uma coisa que experimentei fazer algumas vezes foi tirar um &lt;em&gt;print&lt;/em&gt; da tela do Google Maps de onde eu estava naquele momento e a enviava para o Chat GPT, pedindo dicas de lugares para visitar naquela região, ou dicas de lojas onde eu poderia comprar determinadas coisas que eu estava buscando. O resultado foi bem legal!   Se não fosse ele, eu não teria conhecido, por exemplo, o Kościuszko Mound. Estava ao lado dele mas não estava na minha lista de lugares para conhecer. Fiz o processo que citei acima e ele me recomendou ir para lá, e achei bem legal!&lt;/p&gt;

&lt;h2&gt;
  
  
  Oportunidades de conversas incríveis
&lt;/h2&gt;

&lt;p&gt;Como disse lá no começo, minha maior motivação para ir neste evento era assistir a palestra do Evan Czaplicki e, claro, tinha expectativas dele falar um pouco sobre seu novo projeto, que poucas pessoas tiveram acesso. Quando vi o título da palestra, já imaginei que este não seria o foco - e realmente não foi. Mas e nos bastidores?&lt;/p&gt;

&lt;p&gt;  Durante os dois dias de evento, ele estava conversando com as pessoas do evento, no hall onde ficava o &lt;em&gt;coffee-break&lt;/em&gt;. No primeiro dia eu ensaiei abordá-lo para fazer algumas perguntas, mas minha timidez venceu mais uma vez e fui para o hotel me sentindo derrotado! Lá, disse para mim mesmo: você veio até aqui por conta disso! Se ele estiver lá amanhã, você vai sim falar com ele!! &lt;/p&gt;

&lt;p&gt;E para minha alegria, no dia seguinte ele estava lá novamente, conversando com pessoal. Mais uma vez fiquei com muita vergonha, mas tomei coragem e me aproximei. Não sabia como abordá-lo, apenas cumprimentei ele e a pessoa com quem ele estava conversando com um aceno de cabeça e aguardei a minha vez de falar enquanto, por algum motivo, eles conversavam sobre a cultura japonesa. &lt;/p&gt;

&lt;p&gt;Em um determinado momento ele se virou pra mim e fez um gesto indicando um início de conversa. Me apresentei, agradeci pela palestra, elogiei seu trabalho como programador mas também como palestrante e filosofo, e disse que me inspirava muito em suas palestras. Trocamos algumas palavras e logo depois perguntei sobre seu novo projeto de &lt;em&gt;backend&lt;/em&gt; “secreto”. Fiz alguma pergunta meio genérica sobre do que se tratava e ele ficou pensativo por uns segundos. Fiquei preocupado, confesso. Será que iria receber uma resposta meio atravessada? Será que eu estava sendo muito invasivo? Quem era eu para perguntar sobre um projeto dele que eu sei que ele não está querendo ainda compartilhar com muitas pessoas??  &lt;/p&gt;

&lt;p&gt;Mas após alguns segundos, ele responde: você quer ver? Estou com meu notebook de desenvolvimento aqui, se você tiver uns minutos livre eu posso fazer uma demo pra você.&lt;/p&gt;

&lt;p&gt;Aceitei na hora! Ele pediu para esperar um pouco, que ele iria chamar mais 2 pessoas que estavam interessadas em ver a demo. Logo nos juntamos em uma mesa alta, ali no hall mesmo, onde ele abriu o note e começou a apresentar o projeto. Depois de algum tempo as outras duas pessoas tiveram que sair, e eu estava saindo junto com elas quando ele disse: tenho mais uma demo, não quer ver? E mais uma vez, aceitei entusiasticamente! &lt;/p&gt;

&lt;p&gt;Neste momento ele passou a apresentar a demo apenas para mim. Tirei algumas dúvidas e depois de 40 minutos de conversa, agradeci e me despedi. Nisso ele pergunta a minha opinião sobre o produto, se eu usaria. E em seguida também pergunta minha opinião sobre a demo, se estava boa, se dava para entender a proposta do projeto.&lt;/p&gt;

&lt;p&gt;  Estava eu lá na Polônia, dando minha opinião pessoal para um dos meus ídolos! Que experiência indescritível!! Esses 40 minutos de conversa já fizeram a ida para Polônia valer a pena!&lt;/p&gt;

&lt;h2&gt;
  
  
  Valeu a pena?
&lt;/h2&gt;

&lt;p&gt;Como você já deve imaginar, sim, valeu muito a pena!&lt;/p&gt;

&lt;p&gt;Somando tudo, não foi uma viagem barata. Longe disso! Teve preço da passagem, estadia, ingresso do evento... Tudo pago com dinheiro próprio, sem auxilio da empresa onde trabalho. Por isso, é difícil indicar uma viagem dessas.&lt;/p&gt;

&lt;p&gt;Eu adorei. Me diverti, aprendi, conheci um país diferente, fiz novas amizades... E talvez você conheça pessoas incríveis e consiga o emprego dos seus sonhos? Talvez. Mas é mais provável que não. Se este é seu único objetivo, recomendo que busque na internet mesmo. Nas comunidades, nas redes sociais, escrevendo artigos ou softwares, ...&lt;/p&gt;

&lt;p&gt;Então se você está pensando em fazer algo parecido, faça por prazer. Por diversão. Aí sim, vale muito a pena!&lt;/p&gt;

</description>
      <category>lambdadays</category>
      <category>programaçãofuncional</category>
      <category>elm</category>
      <category>elixir</category>
    </item>
    <item>
      <title>Launch of the Edudu App for iOS and Android</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Thu, 06 Jun 2024 19:20:11 +0000</pubDate>
      <link>https://dev.to/marciofrayze/release-of-edudu-app-1529</link>
      <guid>https://dev.to/marciofrayze/release-of-edudu-app-1529</guid>
      <description>&lt;h2&gt;
  
  
  Release of Edudu
&lt;/h2&gt;

&lt;p&gt;It is with great pleasure that I announce the launch of the Edudu App for &lt;a href="https://apps.apple.com/br/app/edudu/id6477551944" rel="noopener noreferrer"&gt;iOS&lt;/a&gt; and &lt;a href="https://play.google.com/store/apps/details?id=tech.segunda.edudu" rel="noopener noreferrer"&gt;Android&lt;/a&gt;!  &lt;/p&gt;

&lt;p&gt;In this article, I present the Edudu app and discuss the technologies I chose to develop this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Edudu?
&lt;/h2&gt;

&lt;p&gt;If you are a teacher looking for a more efficient way to manage your classes, students, and attendance records, Edudu is the app you have been waiting for!&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class, Student, and Lesson Registration&lt;/strong&gt;: Create and manage multiple classes, keeping all important information organized in one place. Quickly and easily register your students.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Class Diary&lt;/strong&gt;: Record all your lessons and keep track of your students' attendance in a simple and effective way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Storage&lt;/strong&gt;: All data is securely stored in the cloud, ensuring easy access and protection against data loss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intuitive and Easy-to-Use Interface&lt;/strong&gt;: Edudu was developed with ease of use in mind, providing an intuitive experience for users.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technologies
&lt;/h2&gt;

&lt;p&gt;To implement this product, I chose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dart/Flutter&lt;/strong&gt;: I chose the &lt;a href="https://dart.dev" rel="noopener noreferrer"&gt;Dart language&lt;/a&gt; and the &lt;a href="https://flutter.dev" rel="noopener noreferrer"&gt;Flutter framework&lt;/a&gt; because I already have experience with these technologies and was looking for a solution that would allow the creation of an app for both iOS and Android without needing to create two separate codes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://firebase.google.com/docs/auth?hl=en" rel="noopener noreferrer"&gt;Firebase Authentication&lt;/a&gt;&lt;/strong&gt;: Everyone with a smartphone has a Google or Apple account. To facilitate the login process, I use Firebase Authentication for user authentication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://firebase.google.com/docs/firestore?hl=en" rel="noopener noreferrer"&gt;Cloud Firestore&lt;/a&gt;&lt;/strong&gt;: I wanted the data to be maintained in the cloud (not just locally on the user's device). The Firestore database was an almost natural choice. It integrates easily with Firebase Authentication, is secure, fast, and requires minimal maintenance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://firebase.google.com/products/crashlytics?hl=en" rel="noopener noreferrer"&gt;Firebase Crashlytics&lt;/a&gt;&lt;/strong&gt;: Every app needs a mechanism for monitoring failures. Crashlytics fulfills this function very well.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main challenge that led me to choose these technologies was the fact that I was developing this app alone. I was looking for solutions that would allow the construction of a product with reduced effort but with a strong foundation for long-term evolution. Flutter + Firebase proved to be a very good combination for this scenario!&lt;/p&gt;

&lt;p&gt;In the coming months, I intend to write some articles sharing more about this journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where can you find it
&lt;/h2&gt;

&lt;p&gt;The app is free and available on the &lt;a href="https://apps.apple.com/br/app/edudu/id6477551944" rel="noopener noreferrer"&gt;Apple Store&lt;/a&gt; and &lt;a href="https://play.google.com/store/apps/details?id=tech.segunda.edudu" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>app</category>
      <category>ios</category>
      <category>android</category>
      <category>teachers</category>
    </item>
    <item>
      <title>Lançamento do App Edudu</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Thu, 28 Mar 2024 20:11:25 +0000</pubDate>
      <link>https://dev.to/marciofrayze/lancamento-do-app-edudu-o25</link>
      <guid>https://dev.to/marciofrayze/lancamento-do-app-edudu-o25</guid>
      <description>&lt;p&gt;É com muito prazer que anuncio o lançamento do App Edudu &lt;a href="https://apps.apple.com/br/app/edudu/id6477551944" rel="noopener noreferrer"&gt;para iOS&lt;/a&gt; e &lt;a href="https://play.google.com/store/apps/details?id=tech.segunda.edudu" rel="noopener noreferrer"&gt;para Android&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Neste artigo apresento o App e discorro um pouco sobre as tecnologias que escolhi para desenvolver este projeto.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o Edudu?
&lt;/h2&gt;

&lt;p&gt;Se você é um professor ou professora em busca de uma maneira mais eficiente de gerenciar suas turmas, alunos e registros de presença, o Edudu é o aplicativo que você estava esperando!&lt;/p&gt;

&lt;h3&gt;
  
  
  Principais recursos do App:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cadastro de Turmas, Alunos e Aulas&lt;/strong&gt;: Crie e gerencie múltiplas turmas, mantendo todas as informações importantes organizadas em um só lugar. Cadastre seus alunos de forma rápida e fácil.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diário de Classe&lt;/strong&gt;: Registre todas as suas aulas e mantenha o controle das presenças dos seus alunos de forma simples e eficaz.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Armazenamento na Nuvem&lt;/strong&gt;: Todos os dados são armazenados de forma segura na nuvem, garantindo acesso fácil e proteção contra perda de informações.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface intuitiva e fácil de usar&lt;/strong&gt;: O Edudu foi desenvolvido pensando na facilidade de uso, proporcionando uma experiência intuitiva para os usuários.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tecnologias utilizadas
&lt;/h2&gt;

&lt;p&gt;Para implementar este produto, optei por usar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dart/Flutter: escolhi a &lt;a href="https://dart.dev" rel="noopener noreferrer"&gt;linguagem Dart&lt;/a&gt; e o &lt;a href="https://flutter.dev" rel="noopener noreferrer"&gt;framework Flutter&lt;/a&gt; pois já tenho experiência com estas tecnologias e buscava uma solução que permitisse a criação de um App para iOS e para Android sem a necessidade de criar 2 códigos separados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://firebase.google.com/docs/auth?hl=pt-br" rel="noopener noreferrer"&gt;Firebase Authentication&lt;/a&gt;: toda pessoa que possui um &lt;em&gt;smartphone&lt;/em&gt; tem uma conta da Google ou da Apple. Para facilitar o login, utilizo o &lt;em&gt;Firebase Authentication&lt;/em&gt; para fazer a autenticação do usuário.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://firebase.google.com/docs/firestore?hl=pt-br" rel="noopener noreferrer"&gt;Cloud Firestore&lt;/a&gt;: queria que os dados fossem mantidos em uma nuvem (e não apenas localmente no dispositivo da pessoa). O banco de dados &lt;em&gt;Firestore&lt;/em&gt; foi quase uma opção natural. É fácil de integrar com o &lt;em&gt;Firebase Authentication&lt;/em&gt;, seguro, rápido e não exige grandes manutenções.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://firebase.google.com/products/crashlytics?hl=pt-br" rel="noopener noreferrer"&gt;Firebase Crashlytics&lt;/a&gt;: todo App precisa de algum mecanismo de monitoração de falhas. O &lt;em&gt;Crashlytics&lt;/em&gt; cumpre esta função muito bem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O principal obstáculo que me levou a escolher estas tecnologias foi o fato de estar desenvolvendo este App sozinho. Buscava soluções que permitissem a construção de um produto com um esforço reduzido, mas com uma fundação forte que permita uma evolução à longo prazo. Flutter + Firebase se mostrou uma dupla muito boa para este cenário!&lt;/p&gt;

&lt;p&gt;Nos próximos meses pretendo escrever alguns artigos contando um pouco mais sobre esta jornada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde baixar??
&lt;/h2&gt;

&lt;p&gt;O App é gratuito e encontra-se disponível na &lt;a href="https://apps.apple.com/br/app/edudu/id6477551944" rel="noopener noreferrer"&gt;Apple Store&lt;/a&gt; e na &lt;a href="https://play.google.com/store/apps/details?id=tech.segunda.edudu" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>app</category>
      <category>ios</category>
      <category>android</category>
      <category>professores</category>
    </item>
    <item>
      <title>How I developed a web backend in Clojure</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Thu, 06 Jul 2023 13:54:05 +0000</pubDate>
      <link>https://dev.to/marciofrayze/how-i-developed-a-web-backend-in-clojure-4oe7</link>
      <guid>https://dev.to/marciofrayze/how-i-developed-a-web-backend-in-clojure-4oe7</guid>
      <description>&lt;p&gt;One of my students from the course &lt;a href="https://cursos.segunda.tech" rel="noopener noreferrer"&gt;Clojure: Introduction to Functional Programming (Brazilian Portuguese only)&lt;/a&gt; asked an interesting question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hello teacher, I would like to know about the deployment of an application, with a frontend sending requests and getting responses (as in the case of the shopping cart, for example). I'm enjoying the course, but I think a minimal application with a front-end or a service implementation would bring us closer to "real world" usage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although the question is quite outside the scope of the course (which focuses on the concepts of the functional paradigm - the language is just a detail), it is understandable. It is natural to want to know how to apply the new concepts in practice.&lt;/p&gt;

&lt;p&gt;I answered the student, but decided to write this article so I could give a better and more complete response. I will not show how to create a REST service in Clojure step by step, but will give some possible paths, aiming to facilitate the journey of those interested in this topic.&lt;/p&gt;

&lt;p&gt;Throughout this article I show what was my train of thought during the implementation of a REST backend in Clojure that I started developing last year and that I continue to support and add features to this day.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;em&gt;Single Page Application&lt;/em&gt; or &lt;em&gt;Server Side&lt;/em&gt;?
&lt;/h1&gt;

&lt;p&gt;One of the decisions I had to make early on was whether to render the HTML on the backend and use a &lt;strong&gt;fullstack&lt;/strong&gt; Clojure framework or whether to implement a SPA, using Clojure only on the backend (through REST services).&lt;/p&gt;

&lt;p&gt;Clojure supports both approaches. And when choosing to develop a SPA, you can even use Clojure to implement the frontend as well, using &lt;a href="https://clojurescript.org" rel="noopener noreferrer"&gt;ClojureScript&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;But I chose to use Clojure only on the backend and developed the frontend using my favorite programming language: &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wanted to use only functional languages ​​in my &lt;em&gt;stack&lt;/em&gt; and since (at least for now) Elm is focused on frontend development, I needed another language for the backend. As I already wanted to explore the use of the &lt;a href="https://elm.land" rel="noopener noreferrer"&gt;Elm Land&lt;/a&gt; framework and the &lt;a href="https://github.com/mdgriffith/elm-ui" rel="noopener noreferrer"&gt;Elm UI&lt;/a&gt; library, I chose to create a SPA in Elm and use Clojure only on the backend.&lt;/p&gt;

&lt;p&gt;But if you want to, it is possible to implement the whole solution in Clojure.&lt;/p&gt;

&lt;h1&gt;
  
  
  Frameworks or libraries?
&lt;/h1&gt;

&lt;p&gt;In many languages ​​it is common to have web &lt;strong&gt;frameworks&lt;/strong&gt; that includes various functionalities. Anyone who has ever programmed in Java has probably studied &lt;a href="https://spring.io" rel="noopener noreferrer"&gt;Spring&lt;/a&gt; or &lt;a href="https://quarkus.io" rel="noopener noreferrer"&gt;Quarkus&lt;/a&gt;. In Ruby we have the famous Ruby on Rails, in PHP there are solutions like &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt; and &lt;a href="https://symfony.com" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt; (or even the infamous Wordpress), and many others. But there are also many &lt;strong&gt;libraries&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's hard to segment and define what makes a piece of technology to be a framework or a library, and I won't try to do that here. For this article, just consider that while a framework tries to solve many different types of problems, a library tends to have a much smaller scope. Thus, in general, it is necessary to compose a set of libraries to solve a larger problem.&lt;/p&gt;

&lt;p&gt;As examples of libraries, in Ruby I could mention &lt;a href="https://sinatrarb.com" rel="noopener noreferrer"&gt;Sinatra&lt;/a&gt;, for Java/Kotlin &lt;a href="https://sparkjava.com" rel="noopener noreferrer"&gt;Spark&lt;/a&gt;, and many others.&lt;/p&gt;

&lt;p&gt;And as you might guess, there are also frameworks and libraries for web development in Clojure. And one famous framework is &lt;strong&gt;Luminus&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Luminus
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://luminusweb.com" rel="noopener noreferrer"&gt;Luminus&lt;/a&gt; defines itself as a &lt;strong&gt;micro-framework based on a set of lightweight libraries&lt;/strong&gt;. This is a relatively common feature among web frameworks: putting together several small libraries in a cohesive and well-integrated way that, together, have everything usually needed to implement a complete web solution.&lt;/p&gt;

&lt;p&gt;I recommend learning the basics of Luminus to see what is possible to do in Clojure. With it, you can easily create a well-organized project with all the features currently expected in a modern web framework, including a &lt;a href="https://luminusweb.com/docs/migrations.html" rel="noopener noreferrer"&gt;migrations&lt;/a&gt; system for the database schema, automated tests, environment-specific configurations, &lt;a href="https://luminusweb.com/docs/guestbook#accessing_the_database" rel="noopener noreferrer"&gt;some helpers to interact with the database&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;But, while very interesting, it seems to me that this approach is not popular within the Clojure community. What I have observed is that, in general, Clojure developers tend to prefer to choose some libraries and build their own framework, according to their needs.&lt;/p&gt;

&lt;p&gt;And this was also the path I chose to follow: creating my own customized framework for the needs of my project. In part, I went this way because what I had to build wasn’t that complicated. So I took the opportunity to venture into the various libraries of the Clojure universe!&lt;/p&gt;

&lt;h1&gt;
  
  
  Selecting the libraries
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Automation and dependency management
&lt;/h2&gt;

&lt;p&gt;I chose &lt;a href="https://leiningen.org" rel="noopener noreferrer"&gt;Leiningen&lt;/a&gt; to manage project dependencies and automate tasks like running automated tests, generating the project build (&lt;em&gt;Uberjar&lt;/em&gt;), running the REPL terminal (&lt;em&gt;Read-Eval-Print Loop&lt;/em&gt;), etc.&lt;/p&gt;

&lt;p&gt;If you come from the Java world, think of Leiningen as an alternative to &lt;a href="https://maven.apache.org" rel="noopener noreferrer"&gt;Apache Maven&lt;/a&gt; or &lt;a href="https://gradle.org" rel="noopener noreferrer"&gt;Gradle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are other similar tools, but Leiningen seems to be the most used by the Clojure community and it works fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP server
&lt;/h2&gt;

&lt;p&gt;To develop a web application it is necessary, of course, to have a server to receive the requests. For this, I chose the &lt;a href="https://github.com/ring-clojure/ring" rel="noopener noreferrer"&gt;Ring&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;For those familiar with Python, you might think that Ring would be something equivalent to &lt;a href="https://docs.python.org/3/library/wsgiref.html" rel="noopener noreferrer"&gt;WSGI (Web Server Gateway Interface)&lt;/a&gt; and developers used to Ruby might associate it with &lt;a href="https://github.com/rack/rack" rel="noopener noreferrer"&gt;Rack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ring is simple but very low-level and can be tricky to set up. I chose to use the &lt;a href="https://github.com/ring-clojure/ring-defaults" rel="noopener noreferrer"&gt;Ring-Defaults&lt;/a&gt; library, which aims to provide a secure initial configuration that meets most cases. This way it was very easy to configure Ring and create my first REST service in Clojure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route management
&lt;/h2&gt;

&lt;p&gt;Ring is so slim that it doesn't even have a route management system! So I needed to add a library for this purpose.&lt;/p&gt;

&lt;p&gt;For this, I chose to use &lt;a href="https://github.com/weavejester/compojure" rel="noopener noreferrer"&gt;Compojure&lt;/a&gt;. It is a very simple library, which adds some functionalities to Ring related to routes creation.&lt;/p&gt;

&lt;p&gt;Creating a &lt;code&gt;/hello-world&lt;/code&gt; &lt;em&gt;endpoint&lt;/em&gt; using Compojure is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/hello-world"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For complex services you can (and should) delegate the processing of the requests to other functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to the database (PostgreSQL)
&lt;/h2&gt;

&lt;p&gt;With the libraries listed above, it is possible to create a simple server and reply the requests. But most projects will need more than that.&lt;/p&gt;

&lt;p&gt;A common need is to communicate with a database. In my case, I needed to access a PostgreSQL database.&lt;/p&gt;

&lt;p&gt;I chose to use the &lt;a href="https://github.com/clojure/java.jdbc" rel="noopener noreferrer"&gt;clojure.java.jdbc&lt;/a&gt; library. But note that although this library is still maintained (the author continues to apply bug fixes and minor releases), it is described on the website as being &lt;em&gt;"Stable" (no longer "Active")&lt;/em&gt; and they recommend using &lt;a href="https://github.com/seancorfield/next-jdbc" rel="noopener noreferrer"&gt;next-jdbc&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;Therefore, in a new project, I would give priority to this other library (and it is in my plans to migrate the project to it in the future).&lt;/p&gt;

&lt;h3&gt;
  
  
  PostgreSQL
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/clojure/java.jdbc" rel="noopener noreferrer"&gt;clojure.java.jdbc&lt;/a&gt; library is agnostic and can be used on any database with JDBC support (&lt;em&gt;Java Database Connectivity&lt;/em&gt;). To connect to a PostgreSQL database, I also needed to include &lt;a href="https://clojars.org/postgresql" rel="noopener noreferrer"&gt;org.postgresql/postgresql&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Pooling
&lt;/h3&gt;

&lt;p&gt;The two libraries I mentioned above are enough to connect and execute &lt;em&gt;queries&lt;/em&gt; in the database but, for performance reasons, it is important to use a &lt;strong&gt;pool&lt;/strong&gt; of connections. For that I use and recommend &lt;a href="https://github.com/tomekw/hikari-cp" rel="noopener noreferrer"&gt;hikari-cp&lt;/a&gt;. I already used it when programming in Java and it always worked fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the &lt;em&gt;queries&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Developers familiar with object-oriented programming languages (such as Java and C#) should be used to ORM (&lt;em&gt;Object Relational Mapper&lt;/em&gt;) tools like &lt;a href="https://hibernate.org" rel="noopener noreferrer"&gt;Hibernate&lt;/a&gt; or &lt;a href="https://learn.microsoft%20.com/pt-br/ef/" rel="noopener noreferrer"&gt;Entity Framework&lt;/a&gt;. But within the Clojure community, I don't see this type of tool being used much. In the context of Clojure, it is more natural for a database call to return a data structure, such as a map.&lt;/p&gt;

&lt;p&gt;I chose to write the SQL code manually in a few complex &lt;em&gt;queries&lt;/em&gt;, but for most cases I use the &lt;a href="https://github.com/seancorfield/honeysql" rel="noopener noreferrer"&gt;Honey SQL&lt;/a&gt; library. With it, you can build &lt;em&gt;queries&lt;/em&gt; as if they were Clojure data structures.&lt;/p&gt;

&lt;p&gt;An example would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query-select-audit-xpto-by-user-id&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user-id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:created_at&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="no"&gt;:remote_address&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="no"&gt;:raw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"request_headers-&amp;gt;'x-alias'"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:alias&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:audit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user-id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/api/xpto/"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:response_status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/order-by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:desc&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;sql/format&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this function &lt;strong&gt;does not execute&lt;/strong&gt; the &lt;em&gt;query&lt;/em&gt;, it just generates the SQL command, therefore it is a &lt;a href="https://en.wikipedia.org/wiki/Pure_function" rel="noopener noreferrer"&gt;pure function&lt;/a&gt;. When you run it, the result will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;query-select-audit-xpto-by-user-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"123.456.789-01"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Result:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"SELECT created_at, remote_address, request_headers-&amp;gt;'x-alias' AS alias FROM audit WHERE (user_id = ?) AND (path = ?) AND (response_status = ?) AND (method = ?) ORDER BY id DESC"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"123.456.789-01"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/api/xpto/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To actually process it, you have to call the &lt;code&gt;jdbc/with-db-connection&lt;/code&gt; function from the &lt;a href="https://github.com/clojure/java.jdbc" rel="noopener noreferrer"&gt;clojure.java.jdbc&lt;/a&gt; library, passing the &lt;em&gt;query&lt;/em&gt; as a parameter. Before that, of course, you must configure the user, password and address of the database, in addition to the connection pool configuration. But that is beyond the scope of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON
&lt;/h2&gt;

&lt;p&gt;JSON is used very often in web projects. To facilitate the parsing (and generation) of this format, I use the &lt;a href="https://github.com/clojure/data.json" rel="noopener noreferrer"&gt;data.json&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Its use is quite simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;json/write-str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Result:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s"&gt;"{\"a\":1,\"b\":2}"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;json/read-str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"{\"a\":1,\"b\":2}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Result:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performing HTTP calls
&lt;/h2&gt;

&lt;p&gt;In addition to receiving HTTP requests, I needed to integrate with other systems through REST services (another very common need in distributed web applications).&lt;/p&gt;

&lt;p&gt;For that I used the library &lt;a href="https://github.com/dakrone/clj-http" rel="noopener noreferrer"&gt;clj-http&lt;/a&gt; and its use is quite simple. To make a GET call, just run something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;client/get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://example.com/resource/1234"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:accept&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:json&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caching
&lt;/h2&gt;

&lt;p&gt;The system I developed executes a few heavy queries in a large database, to generate some reports. But while those processing are costly, the end result is not a huge amount of data and it doesn't need to be fully up-to-date all the time. Therefore, some of these operations may be cached in memory.&lt;/p&gt;

&lt;p&gt;For that, I used the &lt;a href="https://github.com/clojure/core.cache" rel="noopener noreferrer"&gt;clojure.core.cache&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Although this library works well, I found its interface a bit confusing. To work around this I created my own abstraction. After some tweaks, I managed to create some functions that, although they hide some of the more advanced library functionalities, make the creation of caches quite easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous calls
&lt;/h2&gt;

&lt;p&gt;At a certain point I needed to integrate with the Microsoft Teams chat (through an HTTP call). As I mentioned above, I use &lt;a href="https://github.com/dakrone/clj-http" rel="noopener noreferrer"&gt;clj-http&lt;/a&gt; for this. But I wanted this part of the system to be asynchronous (non-blocking). For this I use the &lt;a href="https://github.com/clojure/core.async" rel="noopener noreferrer"&gt;core.async&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;For those familiar with the Go programming language, this library works similarly to the famous &lt;em&gt;Goroutines&lt;/em&gt;. That is, it is a &lt;em&gt;lightweight thread&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Turning a blocking function into non-blocking is very easy: just pass the expressions/functions you want to run in parallel to the &lt;code&gt;async/go&lt;/code&gt; function. In the case of an HTTP call, it would be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;try&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;client/post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;webhook-teams-url&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;json/write-str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"A message to MS Teams"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="no"&gt;:headers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"content-type"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="no"&gt;:socket-timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="no"&gt;:connection-timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Failed to send message to Teams: "&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scheduler
&lt;/h2&gt;

&lt;p&gt;Another common need for a web application, and which I also needed to do, is scheduling the execution of tasks that must be executed periodically (in my case, executing a function every 10 minutes). For this purpose, I chose to use the &lt;a href="https://github.com/jarohen/chime" rel="noopener noreferrer"&gt;Chime&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Although it is relatively simple, as with the cache library, I initially found it hard to understand how to use it. It's nothing too complex, but I found the documentation a bit confusing. Again I was able to isolate this part of the code in a more specific function and it worked. I had no more problems with it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Mocks and automated tests
&lt;/h1&gt;

&lt;p&gt;I'm a fan of TDD, so I also wanted to create automated tests.&lt;/p&gt;

&lt;p&gt;In the beginning I chose to implement, in addition to the most basic unit tests, several integrated tests. For that I used the &lt;a href="https://github.com/ring-clojure/ring-mock" rel="noopener noreferrer"&gt;Ring-Mock&lt;/a&gt; library to &lt;em&gt;mock&lt;/em&gt; the web server. I also created a &lt;a href="https://www.martinfowler.com/bliki/TestDouble.html" rel="noopener noreferrer"&gt;test double&lt;/a&gt; for the function that accessed the database.&lt;/p&gt;

&lt;p&gt;Over time I began to have trouble maintaining these tests, which broke in non-trivial ways. Another big problem was that when trying to practice TDD I missed a &lt;em&gt;type system&lt;/em&gt; to create the &lt;em&gt;asserts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes I created the entire end-to-end scenario, but at &lt;em&gt;runtime&lt;/em&gt;, when I was running the application and connecting to the real database, the returned type was different from what I was imagining. And again, it was frustrating at times to pinpoint exactly where the problem lay. The error messages were not always meaningful.&lt;/p&gt;

&lt;p&gt;Over time I chose to minimize (at least for now) this type of test. I try to maximize the amount of pure functions and focus my tests on them. I miss testing some layers of the application, which is something I still need to experiment and explore further.&lt;/p&gt;

&lt;h1&gt;
  
  
  Isolating the pure functions
&lt;/h1&gt;

&lt;p&gt;I don't want to go into too much detail about the software architecture in this article, but it's pretty straightforward. Each use case (service) has its own folder, and the pure and impure functions are in different &lt;em&gt;namespaces&lt;/em&gt;. I strive to transform impure functions into pure ones and make those impure ones into orchestrators.&lt;/p&gt;

&lt;p&gt;Functions that cause some kind of side effect should be as "dumb" as possible. For example: a function that executes a &lt;em&gt;query&lt;/em&gt; in the database &lt;strong&gt;cannot have any&lt;/strong&gt; business logic. Same for a function that performs an HTTP call, etc.&lt;/p&gt;

&lt;p&gt;I already considered this to be a good practice when programming in other languages, but in Clojure (due to its functional-first approach), it becomes effortless and natural to do so.&lt;/p&gt;

&lt;p&gt;Over time, I ended up decreasing the number and even eliminating some integrated tests and increasing the amount of unit tests. For my context, this worked fine, but sometimes I still miss broader tests.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dependency injection
&lt;/h1&gt;

&lt;p&gt;Developers used to languages like Java or C# might search for a dependency injection library so they can practice inversion of control.&lt;/p&gt;

&lt;p&gt;To achieve this goal in Clojure, all I've needed so far is to pass function references as parameters. If a function needs, for example, to execute a &lt;em&gt;query&lt;/em&gt; in the database, I pass as a parameter the reference to the function that, when receiving an SQL command, executes it and returns the result. I do the same for HTTP calls or other forms of side effects.&lt;/p&gt;

&lt;p&gt;In the context of my application, this was enough. If I need to create a test double (&lt;em&gt;mock&lt;/em&gt;/&lt;em&gt;spy&lt;/em&gt;/&lt;em&gt;stub&lt;/em&gt;), I just pass the reference of another function as a parameter, avoiding coupling with external layers (such as a database or other systems) in the tests and giving full control over the return in these calls, allowing me to write &lt;em&gt;asserts&lt;/em&gt; that won't break over time. This way my tests can also run concurrently, in addition to being very fast.&lt;/p&gt;

&lt;h1&gt;
  
  
  Hosting
&lt;/h1&gt;

&lt;p&gt;One of the great advantages of Clojure - and one of the main reasons I chose it - is the fact that it is a language that runs on the JVM (Java Virtual Machine). The end result is an &lt;em&gt;Uberjar&lt;/em&gt; (a &lt;em&gt;jar&lt;/em&gt; file with &lt;em&gt;-standalone.jar&lt;/em&gt; suffix) containing all the application and project dependencies.&lt;/p&gt;

&lt;p&gt;And it is possible to start the server with the following command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java -jar target/project-name-0.0.1-SNAPSHOT-standalone.jar

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, I'm using an &lt;em&gt;on-premise&lt;/em&gt; private cloud. And an interesting point is that this cloud already supported the Java platform and I had already developed many solutions in this language. Migrating to Clojure was trivial, not having to make any infrastructure changes. For the operations team, it's completely transparent.&lt;/p&gt;

&lt;p&gt;So applications developed the way I described in this article can be hosted on any server that supports Java! 🎉&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus: Updating dependencies
&lt;/h1&gt;

&lt;p&gt;A concern I always have in every project is to avoid rusting. It is a natural process in every application, so it needs constant attention. And at least for some of these types of problems, the process can be automated!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://leiningen.org" rel="noopener noreferrer"&gt;Leiningen&lt;/a&gt; has a command that checks for outdated dependencies and, if it finds any, is able to update them and then run the automated tests. If any tests fail, the change is undone and an error message is displayed indicating the problem.&lt;/p&gt;

&lt;p&gt;This feature helps me daily! I usually start my day running it to make sure the project's dependencies are always up to date.&lt;/p&gt;

&lt;p&gt;The command in question is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lein ancient upgrade :interactive :check-clojure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But to be able to run it, you need to configure the &lt;a href="https://github.com/xsc/lein-ancient" rel="noopener noreferrer"&gt;lein-ancient&lt;/a&gt; &lt;em&gt;plugin&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  My current &lt;em&gt;project.clj&lt;/em&gt;
&lt;/h1&gt;

&lt;p&gt;All Leiningen configuration is done in the &lt;code&gt;project.clj&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Below I share how my project is set up at the time I write this article. In addition to the libraries I've presented here, I use a few other settings that I didn't find relevant enough to highlight, but that might be useful for some people.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;project-name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.0.0-SNAPSHOT"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Here would be the description of the project."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://git-repository-address"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:min-lein-version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.10.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.11.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-defaults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.3.4"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;com.github.seancorfield/honeysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.4.1045"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/java.jdbc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.12"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.postgresql/postgresql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"42.6.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hikari-cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"3.0.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/data.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.4.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.slf4j/slf4j-simple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.0.7"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clj-http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"3.12.3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/core.cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.0.225"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jarohen/chime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.3.3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/core.async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.6.673"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.12.6"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-cloverage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.2.2"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a.namespace.routes/app&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:repl-options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:init-ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a.namespace.whatever.logic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;javax.servlet/servlet-api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.5"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.4.0"&lt;/span&gt;&lt;span class="p"&gt;]]}})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;Clojure, plus all the libraries that I showed throughout this article, served me very well. I managed to create an architecture that is both simple and easy to add new services. The server consumes few resources and has a very good performance.&lt;/p&gt;

&lt;p&gt;Choosing to create my own framework, selecting each library separately, initially took some time. I had to test each one of them, discard the ones that didn't meet my needs and create some code to "glue" these libraries together.&lt;/p&gt;

&lt;p&gt;Using a full framework (like Luminus) would probably increase my productivity in the first few iterations, but since it's a project I hope to keep for many years, having full control over every part of it is probably the ideal scenario.&lt;/p&gt;

&lt;p&gt;The Clojure community seems to have a culture of crafting small, well-defined purpose libraries. I believe that this characteristic, plus the fact that Clojure is a functional-first language, made this process much easier. These two features together allowed me to be able to create large abstractions by just using function composition, without adding too much complexity.&lt;/p&gt;

&lt;p&gt;But it's important to make it clear that this is a small project, where I didn't need to use any fancy architecture. I didn't cover anything like &lt;em&gt;Domain-driven design&lt;/em&gt;, Hexagonal Architecture, Microservices, ... So I can't say that Clojure (or even the functional paradigm) would be a good fit for complex scenarios. But so far, I'm not regretting the choice and, if it's up to me, I won't be programming in an object-oriented language again anytime soon! 😇&lt;/p&gt;




&lt;p&gt;Did you like this article? &lt;strong&gt;Don't forget to leave a reaction!&lt;/strong&gt; They serve as a big incentive for me to write others.&lt;/p&gt;

&lt;p&gt;You can also discover more articles, podcasts and videos at: &lt;a href="https://segunda.tech/tags/english" rel="noopener noreferrer"&gt;https://segunda.tech/tags/english&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want, follow me on &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="https://staging.bsky.app/profile/segunda.tech" rel="noopener noreferrer"&gt;blue sky&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/marcio-frayze" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Como desenvolvi um backend web em Clojure</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Mon, 03 Jul 2023 11:45:35 +0000</pubDate>
      <link>https://dev.to/marciofrayze/como-desenvolvi-um-backend-web-em-clojure-2k67</link>
      <guid>https://dev.to/marciofrayze/como-desenvolvi-um-backend-web-em-clojure-2k67</guid>
      <description>&lt;p&gt;Um dos meus alunos do curso &lt;a href="https://cursos.segunda.tech" rel="noopener noreferrer"&gt;Clojure: Introdução à Programação Funcional&lt;/a&gt; fez uma pergunta interessante:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Olá professor, gostaria de informações sobre o deploy de uma aplicação, com um frontend enviando solicitações e obtendo repostas (como no caso do carrinho de compras, por exemplo). Estou gostando do curso, porém acho que uma construção mínima com um front-end ou implementado um service nos aproximaria mais do uso "no mundo real".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Embora a pergunta fuja bastante do escopo do curso (cujo foco são os conceitos do paradigma funcional - a linguagem em si é um detalhe), é uma dúvida bastante compreensível. É natural querer saber como aplicar os conhecimentos na prática.&lt;/p&gt;

&lt;p&gt;Respondi o aluno, mas resolvi criar este artigo para poder explicar de forma mais completa. Não irei mostrar o passo a passo de como criar um serviço REST em Clojure, mas vou dar alguns caminhos possíveis, visando facilitar a trajetória daquelas pessoas interessadas neste tema.&lt;/p&gt;

&lt;p&gt;Ao longo do artigo mostro como foi a minha linha de raciocínio para implementar um backend REST em Clojure que comecei a desenvolver ano passado e que continuo sustentando e adicionando funcionalidades.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;em&gt;Single Page Application&lt;/em&gt; ou &lt;em&gt;Server Side&lt;/em&gt;?
&lt;/h1&gt;

&lt;p&gt;Uma das decisões que precisei tomar logo no início foi se iria renderizar o HTML no backend e utilizar um framework Clojure &lt;strong&gt;fullstack&lt;/strong&gt; ou se iria implementar um SPA, utilizando o Clojure apenas no backend (através de serviços REST).&lt;/p&gt;

&lt;p&gt;Clojure permite as duas abordagens. E ao escolher desenvolver um SPA, você pode até mesmo utilizar Clojure para implementar também o frontend, utilizando &lt;a href="https://clojurescript.org" rel="noopener noreferrer"&gt;ClojureScript&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Mas optei por utilizar Clojure apenas no backend e desenvolvi o frontend utilizando minha linguagem de programação favorita: &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Queria utilizar apenas linguagens funcionais em toda a &lt;em&gt;stack&lt;/em&gt; e como (pelo menos por enquanto) Elm é uma linguagem focada no desenvolvimento de frontends, precisava de outra linguagem para o backend. Como já queria explorar o uso do framework &lt;a href="https://elm.land" rel="noopener noreferrer"&gt;Elm Land&lt;/a&gt; e a biblioteca &lt;a href="https://github.com/mdgriffith/elm-ui" rel="noopener noreferrer"&gt;Elm UI&lt;/a&gt;, optei por criar um SPA em Elm e utilizar Clojure apenas no backend.&lt;/p&gt;

&lt;p&gt;Mas é possível implementar toda a solução em Clojure, caso você ache interessante.&lt;/p&gt;

&lt;h1&gt;
  
  
  Frameworks ou bibliotecas?
&lt;/h1&gt;

&lt;p&gt;Em muitas linguagens é comum existirem &lt;strong&gt;frameworks&lt;/strong&gt; web que agregam diversas funcionalidades. Quem já programou em Java provavelmente já estudou sobre o &lt;a href="https://spring.io" rel="noopener noreferrer"&gt;Spring&lt;/a&gt; ou &lt;a href="https://quarkus.io" rel="noopener noreferrer"&gt;Quarkus&lt;/a&gt;. Já em Ruby temos o famoso Ruby on Rails, no PHP existem soluções como &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt; e &lt;a href="https://symfony.com" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt; (ou ainda o famigerado Wordpress), entre tantos outros possíveis exemplos. Mas existem também muitas &lt;strong&gt;bibliotecas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;É difícil segmentar e definir o que faz com que uma tecnologia seja considerada um frameworks ou uma biblioteca, e não vou tentar fazer isso aqui. Para este artigo, basta considerar que enquanto um framework tenta resolver diversos tipos diferentes de problemas, uma biblioteca costuma ter um escopo bem mais reduzido. Desta forma, em geral, é necessário compor um conjunto de bibliotecas para solucionar um problema maior.&lt;/p&gt;

&lt;p&gt;Como exemplos de bibliotecas para o universo web, no Ruby poderia citar o &lt;a href="https://sinatrarb.com" rel="noopener noreferrer"&gt;Sinatra&lt;/a&gt;, para Java/Kotlin o &lt;a href="https://sparkjava.com" rel="noopener noreferrer"&gt;Spark&lt;/a&gt;, entre muitos outros.&lt;/p&gt;

&lt;p&gt;E como você deve imaginar, existem também frameworks e bibliotecas para desenvolvimento web em Clojure. E um framework famoso é o &lt;strong&gt;Luminus&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Luminus
&lt;/h1&gt;

&lt;p&gt;O &lt;a href="https://luminusweb.com" rel="noopener noreferrer"&gt;Luminus&lt;/a&gt; se classifica como um &lt;strong&gt;micro-framework Clojure, baseado em um conjunto de bibliotecas leves&lt;/strong&gt;. Esta é uma característica relativamente comum entre os frameworks web: juntar diversas pequenas bibliotecas de forma coesa e bem integrada que, juntas, possuem tudo que normalmente é necessário para implementar uma solução web completa.&lt;/p&gt;

&lt;p&gt;Vale muito a pena conhecer este projeto e ver o que é possível fazer em Clojure. Com ele, você poderá criar facilmente um projeto muito bem organizado e com todas as funcionalidades esperadas atualmente, incluindo um sistema de &lt;a href="https://luminusweb.com/docs/migrations.html" rel="noopener noreferrer"&gt;migrations&lt;/a&gt; do schema do banco de dados, testes automatizados, configurações separadas por ambientes, &lt;a href="https://luminusweb.com/docs/guestbook#accessing_the_database" rel="noopener noreferrer"&gt;algumas facilidades para interagir com banco de dados&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;Mas, embora muito bacana, me parece que esta não é uma abordagem tão popular dentro da comunidade Clojure. O que tenho observado é que, em geral, as pessoas desenvolvedoras Clojure costumam preferir escolher algumas bibliotecas e montar o seu próprio framework, de acordo com suas necessidades.&lt;/p&gt;

&lt;p&gt;E este também foi o caminho que escolhi seguir: criar o meu próprio framework customizado para as necessidades do meu projeto. Em parte, segui este caminho pois o que precisava construir não era algo tão complexo assim. Aproveitei então para me aventurar nas diversas bibliotecas do mundo Clojure!&lt;/p&gt;

&lt;h1&gt;
  
  
  Selecionando as bibliotecas
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Automação e gestão de dependências
&lt;/h2&gt;

&lt;p&gt;Escolhi o &lt;a href="https://leiningen.org" rel="noopener noreferrer"&gt;Leiningen&lt;/a&gt; para gerenciar as dependências do projeto e automatizar tarefas como executar testes automatizados, gerar a &lt;em&gt;build&lt;/em&gt; (&lt;em&gt;Uberjar&lt;/em&gt;) do projeto, executar o terminal do REPL (&lt;em&gt;Read-Eval-Print Loop&lt;/em&gt;), etc.&lt;/p&gt;

&lt;p&gt;Se você vem do mundo Java, pense no Leiningen como sendo uma alternativa ao &lt;a href="https://maven.apache.org" rel="noopener noreferrer"&gt;Apache Maven&lt;/a&gt; ou &lt;a href="https://gradle.org" rel="noopener noreferrer"&gt;Gradle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Existem outras ferramentas similares, mas o Leiningen parece ser a mais utilizada no universo Clojure e atendeu bem minhas necessidades.&lt;/p&gt;

&lt;h2&gt;
  
  
  Servidor HTTP
&lt;/h2&gt;

&lt;p&gt;Para desenvolver uma aplicação web é necessário, claro, ter um servidor para receber as requisições. Para isso, escolhi a biblioteca &lt;a href="https://github.com/ring-clojure/ring" rel="noopener noreferrer"&gt;Ring&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para quem conhece Python, pode pensar que Ring seria algo equivalente ao &lt;a href="https://docs.python.org/3/library/wsgiref.html" rel="noopener noreferrer"&gt;WSGI (Web Server Gateway Interface)&lt;/a&gt; e o pessoal acostumado com Ruby pode associá-la ao &lt;a href="https://github.com/rack/rack" rel="noopener noreferrer"&gt;Rack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ring é uma biblioteca simples, mas de baixo nível de abstração. Por isso pode ser um pouco complicada de configurar. Optei então por utilizar a biblioteca &lt;a href="https://github.com/ring-clojure/ring-defaults" rel="noopener noreferrer"&gt;Ring-Defaults&lt;/a&gt;, que tem como objetivo prover uma configuração inicial segura e que atenda a maioria dos casos. Com ela foi muito fácil configurar o Ring e criar meus primeiros serviços REST.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gerenciador de rotas
&lt;/h2&gt;

&lt;p&gt;Ring é tão enchuta que não conta nem mesmo com um sistema de gerenciamento de rotas! Então precisei acrescentar uma biblioteca para esta finalidade.&lt;/p&gt;

&lt;p&gt;Para isso, escolhi utilizar a &lt;a href="https://github.com/weavejester/compojure" rel="noopener noreferrer"&gt;Compojure&lt;/a&gt;. Trata-se de uma biblioteca bastante simples, que acrescenta algumas facilidades ao Ring relacionadas à criação de rotas.&lt;/p&gt;

&lt;p&gt;Criar um &lt;em&gt;endpoint&lt;/em&gt; &lt;code&gt;/ola-mundo&lt;/code&gt; utilizando a Compojure é bastante fácil:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/ola-mundo"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Olá Mundo&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas claro que para serviços mais complexos você pode (e deve) delegar o processamento das requisições para outras funções.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conectando ao banco de dados (PostgreSQL)
&lt;/h2&gt;

&lt;p&gt;Com as bibliotecas listadas acima, já é possível criar um servidor simples e retornar as requisições. Mas a maioria dos projetos vai precisar mais do que isso.&lt;/p&gt;

&lt;p&gt;Uma necessidade comum é se comunicar com um banco de dados. No meu caso, precisava acessar um banco PostgreSQL.&lt;/p&gt;

&lt;p&gt;Optei por utilizar a biblioteca &lt;a href="https://github.com/clojure/java.jdbc" rel="noopener noreferrer"&gt;clojure.java.jdbc&lt;/a&gt;. Mas note que, embora esta biblioteca ainda seja mantida (o autor continue aplicacando &lt;em&gt;patchs&lt;/em&gt; de correções), ela está descrita no site como sendo &lt;em&gt;"Estável" (não mais "Ativa")&lt;/em&gt;. O site ainda recomenda que em seu lugar seja utilizada a &lt;a href="https://github.com/seancorfield/next-jdbc" rel="noopener noreferrer"&gt;next-jdbc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Portando, em um projeto novo, eu daria prioridade à esta outra biblioteca (e está em meus planos migrar o projeto para ela no futuro).&lt;/p&gt;

&lt;h3&gt;
  
  
  PostgreSQL
&lt;/h3&gt;

&lt;p&gt;A biblioteca &lt;a href="https://github.com/clojure/java.jdbc" rel="noopener noreferrer"&gt;clojure.java.jdbc&lt;/a&gt; é agnostica e pode ser usada em qualquer banco de dados com suporte ao JDBC (&lt;em&gt;Java Database Connectivity&lt;/em&gt;) e para conseguir me conectar ao banco PostgreSQL, também precisei utilizar a &lt;a href="https://clojars.org/postgresql" rel="noopener noreferrer"&gt;org.postgresql/postgresql&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pool de conexões
&lt;/h3&gt;

&lt;p&gt;As duas bibliotecas que citei acima são suficientes para conectar e executar &lt;em&gt;queries&lt;/em&gt; no banco mas, por questões de performance, é importante utilizar um &lt;em&gt;pool&lt;/em&gt; de conexões. Para isso utilizei e recomendo a &lt;a href="https://github.com/tomekw/hikari-cp" rel="noopener noreferrer"&gt;hikari-cp&lt;/a&gt;. Já utilizava ela quando programava em Java e sempre me atendeu muito bem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando as &lt;em&gt;queries&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Pessoas que estão acostumadas com Java, C# e similares, devem estar habituadas a utilizar ferramentas de ORM (&lt;em&gt;Object Relational Mapper&lt;/em&gt;) como &lt;a href="https://hibernate.org" rel="noopener noreferrer"&gt;Hibernate&lt;/a&gt; ou &lt;a href="https://learn.microsoft.com/pt-br/ef/" rel="noopener noreferrer"&gt;Entity Framework&lt;/a&gt;. Mas dentro da comunidade Clojure, não vejo este tipo de ferramenta sendo muito utilizada. No contexto de Clojure, é mais natural que uma chamada ao banco retorne uma estrutura da dados, como um mapa.&lt;/p&gt;

&lt;p&gt;Optei por escrever o código SQL manualmente em algumas poucas &lt;em&gt;queries&lt;/em&gt; mais complexas, mas para a maioria dos casos utilizei a biblioteca &lt;a href="https://github.com/seancorfield/honeysql" rel="noopener noreferrer"&gt;Honey SQL&lt;/a&gt;. Com ela é possível construir as &lt;em&gt;queries&lt;/em&gt; como se fossem estruturas de dados Clojure.&lt;/p&gt;

&lt;p&gt;Um exemplo seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query-select-auditoria-xpto-por-cpf&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cpf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:created_at&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="no"&gt;:remote_address&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="no"&gt;:raw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"request_headers-&amp;gt;'x-alias'"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:alias&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:auditoria&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:cpf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/api/xpto/"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:response_status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/order-by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:desc&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;sql/format&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note que esta função &lt;strong&gt;não executa&lt;/strong&gt; a &lt;em&gt;query&lt;/em&gt;, apenas gera o comando SQL, sendo portanto uma &lt;a href="https://www.youtube.com/watch?v=QenAR_3XtXU" rel="noopener noreferrer"&gt;função pura&lt;/a&gt;. Ao executá-la, o seu resultado será:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;query-select-auditoria-xpto-por-cpf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"123.345.789-01"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;;; Resultado:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"SELECT created_at, remote_address, request_headers-&amp;gt;'x-alias' AS alias FROM auditoria WHERE (cpf = ?) AND (path = ?) AND (response_status = ?) AND (method = ?) ORDER BY id DESC"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"123.345.789-01"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/api/xpto/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para processá-la de fato, é necessário chamar a função &lt;code&gt;jdbc/with-db-connection&lt;/code&gt; da biblioteca &lt;a href="https://github.com/clojure/java.jdbc" rel="noopener noreferrer"&gt;clojure.java.jdbc&lt;/a&gt;, passando a &lt;em&gt;query&lt;/em&gt; que deseja executar como parâmetro. Antes disso, claro, precisa configurar usuário, senha e endereço do banco, além do &lt;em&gt;pool&lt;/em&gt; de conexões. Mas isso já foge do escopo deste artigo.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON
&lt;/h2&gt;

&lt;p&gt;O padrão JSON é utilizado com muita frequência em projetos web. Para facilitar o &lt;em&gt;parsing&lt;/em&gt; (e geração) deste formato, utilizo a biblioteca &lt;a href="https://github.com/clojure/data.json" rel="noopener noreferrer"&gt;data.json&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Seu uso é bastante simples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;json/write-str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Resultado:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s"&gt;"{\"a\":1,\"b\":2}"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;json/read-str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"{\"a\":1,\"b\":2}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Resultado:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Executando chamadas HTTP
&lt;/h2&gt;

&lt;p&gt;Além de receber requisições HTTP, eu precisava me integrar com outros sistemas através de serviços REST (outra necessidade bastante comum em aplicações web distribuídas).&lt;/p&gt;

&lt;p&gt;Para isso utilizei a biblioteca &lt;a href="https://github.com/dakrone/clj-http" rel="noopener noreferrer"&gt;clj-http&lt;/a&gt; e seu uso é bastante simples. Para fazer uma chamada GET, basta executar algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;client/get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://exemplo.com/recurso/1234"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:accept&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:json&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caching
&lt;/h2&gt;

&lt;p&gt;O sistema que desenvolvi executa algumas &lt;em&gt;queries&lt;/em&gt; pesadas no banco, para geração de relatórios. Mas embora o processamento seja oneroso, o resultado final não é um volume grande de dados e não precisa estar totalmente atualizado o tempo todo. Por isso, algumas destas operações podem ser cacheadas em memória.&lt;/p&gt;

&lt;p&gt;Para isso, utilizei a biblioteca &lt;a href="https://github.com/clojure/core.cache" rel="noopener noreferrer"&gt;clojure.core.cache&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Embora esta biblioteca funcione bem, achei a sua interface um pouco confusa. Para contornar isso criei a minha própria abstração. Depois de alguns ajustes, consegui criar algumas funções que, embora escondam algumas funções mais avançadas da biblioteca, tornam a utilização do cache bastante simples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chamadas assíncronas
&lt;/h2&gt;

&lt;p&gt;Em um determinado momento precisei fazer uma integração com o chat do Microsoft Teams (através de uma chamada HTTP). Como já mencionei acima, utilizei a &lt;a href="https://github.com/dakrone/clj-http" rel="noopener noreferrer"&gt;clj-http&lt;/a&gt; para isso. Mas queria que esta parte do sistema fosse assíncrona (não bloqueante). Para isso utilizei a biblioteca &lt;a href="https://github.com/clojure/core.async" rel="noopener noreferrer"&gt;core.async&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para quem conhece a linguagem Go, esta biblioteca funciona de forma parecida com as famosas &lt;em&gt;Goroutines&lt;/em&gt;. Ou seja, é uma &lt;em&gt;lightweight thread&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Tornar uma função bloqueante em não-bloqueante é muito fácil: basta passar as expressões/funções que deseja executar em paralelo para a função &lt;code&gt;async/go&lt;/code&gt;. No caso de uma chamada HTTP, seria algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;async/go&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;try&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;client/post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;url-webhook-teams&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;json/write-str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Uma mensagem para o MS Teams"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="no"&gt;:headers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"content-type"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="no"&gt;:socket-timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="w"&gt;      
                  &lt;/span&gt;&lt;span class="no"&gt;:connection-timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Falha ao tentar enviar mensagem para o Teams: "&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Agendamento de execuções (&lt;em&gt;scheduler&lt;/em&gt;)
&lt;/h2&gt;

&lt;p&gt;Outra necessidade comum de uma aplicação web, e que também precisei fazer, é o agendamento de execução de tarefas que devem ser executadas de forma periódicas (no meu caso, executar uma função a cada 10 minutos). Para esta finalidade, utilizei a biblioteca &lt;a href="https://github.com/jarohen/chime" rel="noopener noreferrer"&gt;Chime&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Embora seja relativamente simples, assim como ocorreu com a biblioteca de cache, inicialmente tive um pouco de dificuldade para entender como utilizá-la. Não é nada muito complexo, mas achei a documentação um pouco confusa. Novamente consegui isolar esta parte do código em uma função mais específica e deu tudo certo. Não tive mais problemas com ela.&lt;/p&gt;

&lt;h1&gt;
  
  
  Mocks e testes automatizados
&lt;/h1&gt;

&lt;p&gt;Além do código de produção, queria criar testes automatizados.&lt;/p&gt;

&lt;p&gt;Nos primeiros serviços optei por implementar, além dos testes unitários mais básicos, vários testes integrados. Para isso utilizei a biblioteca &lt;a href="https://github.com/ring-clojure/ring-mock" rel="noopener noreferrer"&gt;Ring-Mock&lt;/a&gt; para &lt;em&gt;mockar&lt;/em&gt; o servidor web. Também criei um dublê da função que fazia acesso ao banco de dados.&lt;/p&gt;

&lt;p&gt;Com o tempo comecei a ter dificuldade para manter estes testes, que quebravam de forma não muito trivial. Outro grande problema era que, ao tentar praticar TDD, senti falta de um &lt;em&gt;type system&lt;/em&gt; para criar os &lt;em&gt;asserts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Às vezes criava todo o cenário de ponta a ponta, mas em &lt;em&gt;runtime&lt;/em&gt;, quando estava executando a aplicação e me conectando no banco real, o tipo retornado era diferente do que eu estava imaginando. E mais uma vez encontrar exatamente onde estava o problema era um pouco chato às vezes. Nem sempre a mensagem de erro era realmente significativa.&lt;/p&gt;

&lt;p&gt;Com o tempo optei por minimizar (pelo menos por enquanto) este tipo de teste. Tento maximizar a quantidade de funções puras e foco meus testes nelas. Sinto falta de testar algumas camadas da aplicação, sendo algo que ainda preciso experimentar e explorar mais.&lt;/p&gt;

&lt;h1&gt;
  
  
  Separando as funções puras
&lt;/h1&gt;

&lt;p&gt;Não quero entrar muito em detalhes da arquitetura do sistema neste artigo, mas ela está bastante simples. Cada caso de uso (serviço) tem a sua própria pasta, e as funções puras e impuras estão em &lt;em&gt;namespaces&lt;/em&gt; distintos. Me esforço para tentar transformar funções impuras em puras e tornar aquelas impuras em apenas orquestradoras.&lt;/p&gt;

&lt;p&gt;As funções que causam algum tipo de efeito colateral devem ser o mais "burras" possível. Exemplo: uma função que executa uma &lt;em&gt;query&lt;/em&gt; no banco não pode ter &lt;strong&gt;nenhuma&lt;/strong&gt; regra de negócio. O mesmo para uma função que executa uma chamada HTTP, etc.&lt;/p&gt;

&lt;p&gt;Já considerava isso uma boa prática quando programava em outras linguagens, mas em Clojure (por ser funcional), torna-se muito fácil e natural fazer isso.&lt;/p&gt;

&lt;p&gt;Com o tempo, acabei diminuindo e até eliminando alguns testes integrados e aumentando a quantidade de testes unitários. Para o meu contexto, isso funcionou bem, mas às vezes ainda sinto falta de testes mais abrangentes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Injeção de dependências
&lt;/h1&gt;

&lt;p&gt;Pessoas acostumadas com Java, .NET e similares talvez queiram buscar alguma biblioteca de injeção de dependência para poder praticar inversão de controle.&lt;/p&gt;

&lt;p&gt;Para atingir este objetivo em Clojure, tudo que precisei até agora foi passar referências de funções como parâmetros. Se uma função precisa, por exemplo, executar uma &lt;em&gt;query&lt;/em&gt; no banco de dados, eu passo como parâmetro a referência para a função que, ao receber um comando SQL, o executa e retorna o resultado. Faço o mesmo para chamadas HTTP ou outras formas de efeitos colaterais.&lt;/p&gt;

&lt;p&gt;No contexto da minha aplicação, isso foi suficiente. Caso precise criar um dublê (&lt;em&gt;mock&lt;/em&gt;/&lt;em&gt;spy&lt;/em&gt;/&lt;em&gt;stub&lt;/em&gt;), basta passar a referência de outra função (usada apenas para testes) como parâmetro. Assim consigo evitar o acoplamento com camadas externas (como banco de dados ou outros sistemas) nos testes, permitindo que tenha total controle sobre o que será retornado nessas chamadas, permitindo criar &lt;em&gt;asserts&lt;/em&gt; facilmente, que não irão quebrar com o tempo. Isso permite também que meus testes possam ser executados de forma concorrente, além de serem muito rápidos.&lt;/p&gt;

&lt;h1&gt;
  
  
  Onde hospedar
&lt;/h1&gt;

&lt;p&gt;Uma das grandes vantagens da linguagem Clojure - e um dos principais motivos de tê-la escolhido - é o fato de ser uma linguagem que roda na JVM (Java Virtual Machine). O resultado final da aplicação é um &lt;em&gt;Uberjar&lt;/em&gt; (um arquivo &lt;em&gt;jar&lt;/em&gt; com sufixo &lt;em&gt;-standalone.jar&lt;/em&gt;) contendo toda a aplicação e dependências do projeto.&lt;/p&gt;

&lt;p&gt;E o servidor criado da forma como descrevi neste artigo pode ser iniciado no ambiente produtivo com a seguinte linha de comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java -jar target/nome-projeto-0.0.1-SNAPSHOT-standalone.jar

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No meu caso, estou utilizando uma nuvem privada &lt;em&gt;on-premise&lt;/em&gt;. E um ponto interessante é que esta nuvem já tinha suporte à plataforma Java e eu já havia desenvolvido muitas soluções nesta linguagem. Migrar para o Clojure foi trivial, não precisando fazer nenhuma alteração na infraestrutura. Para o time do centro de dados, é totalmente transparente.&lt;/p&gt;

&lt;p&gt;Ou seja, aplicações desenvolvidas da forma como descrevi neste artigo podem ser hospedadas em qualquer servidor que tenha suporte ao Java! 🎉&lt;/p&gt;

&lt;h1&gt;
  
  
  Bônus: atualizando as dependências
&lt;/h1&gt;

&lt;p&gt;Uma preocupação que sempre tenho em todo projeto é evitar o seu envelhecimento. É um processo natural de toda aplicação, que precisa de atenção constânte do time. E pelo menos para alguns destes tipos de problemas, o processo pode ser automatizado!&lt;/p&gt;

&lt;p&gt;O &lt;a href="https://leiningen.org" rel="noopener noreferrer"&gt;Leiningen&lt;/a&gt; possui um comando que verifica se existem dependências desatualizadas e, caso encontre alguma, é capaz de atualizá-la e em seguida executar os testes automatizados. Caso algum teste falhe, a alteração é desfeita e uma mensagem de erro é exibida indicando o problema.&lt;/p&gt;

&lt;p&gt;Esta funcionalidade me ajuda diariamente! Criei um script com o comando e normalmente começo meu dia executando-o para garantir que o projeto está com as dependências sempre atualizadas.&lt;/p&gt;

&lt;p&gt;O comando em questão é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lein ancient upgrade :interactive :check-clojure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas para poder executá-lo é necessário configurar o &lt;em&gt;plugin&lt;/em&gt; &lt;a href="https://github.com/xsc/lein-ancient" rel="noopener noreferrer"&gt;lein-ancient&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Meu &lt;em&gt;project.clj&lt;/em&gt; atual
&lt;/h1&gt;

&lt;p&gt;A configuração de um projeto que utilize o Leiningen é toda feita no arquivo &lt;code&gt;project.clj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Abaixo compartilho como está a configuração do meu projeto no momento em que estou escrevendo este texto. Além das bibliotecas que aprensentei aqui, utilizo algumas outras configurações que não achei relevantes o suficiente para destacar, mas que podem ser úteis para algumas pessoas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nome-projeto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.0.0-SNAPSHOT"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Aqui ficaria a descrição do projeto."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://endereço-repositorio-git"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:min-lein-version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.10.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.11.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;compojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-defaults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.3.4"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;com.github.seancorfield/honeysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.4.1045"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/java.jdbc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.12"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.postgresql/postgresql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"42.6.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hikari-cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"3.0.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/data.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.4.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.slf4j/slf4j-simple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.0.7"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clj-http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"3.12.3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/core.cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.0.225"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jarohen/chime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.3.3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;org.clojure/core.async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.6.673"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;lein-ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.12.6"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.7.0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lein-cloverage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"1.2.2"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:ring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;um.namespace.qualquer.routes/app&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:repl-options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:init-ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;um.namespace.qualquer.logic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="no"&gt;:profiles&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;javax.servlet/servlet-api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"2.5"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ring/ring-mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.4.0"&lt;/span&gt;&lt;span class="p"&gt;]]}})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusões
&lt;/h1&gt;

&lt;p&gt;Clojure, em conjunto com as bibliotecas que mostrei ao longo deste artigo, me atenderam muito bem. Consegui criar uma arquitetura que é ao mesmo tempo simples e fácil de incluir novos serviços. O servidor consome poucos recursos e tem uma performance muito boa.&lt;/p&gt;

&lt;p&gt;A escolha por criar o meu próprio framework, selecionando cada biblioteca isoladamente, inicialmente consumiu certo tempo. Tive que testar cada uma delas, descartar as que não atendiam minhas necessidades e construir alguns códigos para "colar" essas bibliotecas. &lt;/p&gt;

&lt;p&gt;Usar um framework pronto provavelmente iria aumentar a minha produtividade nas primeiras iterações, mas como é um projeto que espero manter por muitos anos, ter total controle sobre cada parte dele provavelmente é o cenário ideal.&lt;/p&gt;

&lt;p&gt;A comunidade Clojure parece ter uma cultura de criar bibliotecas pequenas, com propósitos muito bem definidos. Acredito que esta característica, em conjunto com o fato de Clojure ser uma linguagem funcional, facilitou muito este processo. Essas duas características somadas permitiram que, apenas utilizando composição de funções, eu fosse capaz de criar grandes abstrações, sem adicionar muita complexidade.&lt;/p&gt;

&lt;p&gt;Mas é importante deixar claro que este é um projeto pequeno, onde não precisei utilizar nenhuma arquitetura muito avançada. Não abordei nada como &lt;em&gt;Domain-driven design&lt;/em&gt;, Arquitetura Hexagonal, Microsserviços, ... Então não consigo afirmar que Clojure (ou mesmo o paradigma funcional) seria uma boa opção para cenários mais complexos. Mas, até o momento, não estou arrependido da escolha e, se depender de mim, não volto a programar em uma linguagem orientada a objetos novamente tão cedo! 😇&lt;/p&gt;




&lt;p&gt;E você? Quais tecnologias têm utilizado para desenvolvimento web? Conte um pouco das suas experiências mais recentes nos comentários!&lt;/p&gt;




&lt;p&gt;Gostou deste texto? Conheça meus outros artigos, podcasts e vídeos acessando: &lt;a href="https://segunda.tech" rel="noopener noreferrer"&gt;https://segunda.tech&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;E se quiser, me segue lá no &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt; e &lt;a href="https://staging.bsky.app/profile/segunda.tech" rel="noopener noreferrer"&gt;blue sky&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>backend</category>
    </item>
    <item>
      <title>What it was like to spend a month using GitHub Copilot and why I plan to not use it (next month)</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Thu, 15 Jun 2023 13:57:57 +0000</pubDate>
      <link>https://dev.to/marciofrayze/what-it-was-like-to-spend-a-month-using-github-copilot-and-why-i-plan-to-not-use-it-next-month-3ao5</link>
      <guid>https://dev.to/marciofrayze/what-it-was-like-to-spend-a-month-using-github-copilot-and-why-i-plan-to-not-use-it-next-month-3ao5</guid>
      <description>&lt;p&gt;You're probably already familiar with &lt;a href="https://github.com/features/copilot/?ref=heydesigner" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;: a tool created by Microsoft to help developers by providing real-time code suggestions. While tools like ChatGPT are also capable of generating code, GitHub Copilot takes advantage of tight integration with the code editor.&lt;/p&gt;

&lt;p&gt;There are several ways to use it: you can write a feature as a comment and the tool is capable of generating a function, method, or even a complete class to contemplate what you described. Or you can type the name of a function or method and let the autocomplete try to predict the corresponding code. Or you can just use it as a slightly "smarter" autocomplete for smaller parts of your code.&lt;/p&gt;

&lt;p&gt;The first way (using only comments) I don't trust and would never recommend. The second, writing just the name of the function or method, usually works surprisingly well for snippets of code with reduced and closed scope, such as creating a function that will receive a data structure and do some simple transformation or filter operations. The last way, as a more "efficient" autocomplete, had mixed results. Sometimes it hit the jackpot! 🎯 But it wasn't uncommon to need adjustments or even come up with a solution that was just plain wrong.&lt;/p&gt;

&lt;p&gt;Throughout May 2023, I used this tool to program in &lt;a href="https://clojure.org" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt; and &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;. In this article, I tell you a little about what I thought of this experience.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why I decided to give it a try
&lt;/h1&gt;

&lt;p&gt;In April 2023 Kent Beck posted &lt;a href="https://twitter.com/KentBeck/status/1648413998025707520?s=20" rel="noopener noreferrer"&gt;the following message on Twitter&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffho2oytlo8iock53258j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffho2oytlo8iock53258j.png" alt="Kent Beck: I’ve been reluctant to try ChatGPT. Today I got over that reluctance. Now I understand why I was reluctant. The value of 90% of my skills just dropped to $0. The leverage for the remaining 10% went up 1000x. I need to recalibrate." width="589" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This twit was so successful that he ended up &lt;a href="https://tidyfirst.substack.com/p/90-of-my-skills-are-now-worth-0" rel="noopener noreferrer"&gt;writing a post&lt;/a&gt; to better explain his opinion.&lt;/p&gt;

&lt;p&gt;For those who don't know him, Kent Beck is one of my favorite technical book authors, having written such books as &lt;a href="https://www.goodreads.com/book/show/67833.Extreme_Programming_Explained" rel="noopener noreferrer"&gt;eXtreme Programming Explained&lt;/a&gt;, &lt;a href="https://www.goodreads.com/book/show/67839.Planning_Extreme_Programming" rel="noopener noreferrer"&gt;Planning Extreme Programming &lt;/a&gt;, &lt;a href="https://www.goodreads.com/book/show/387190.Test_Driven_Development" rel="noopener noreferrer"&gt;Test-Driven Development: By Example&lt;/a&gt;, among &lt;a href="https://www.goodreads.com/author/list/25211.Kent_Beck" rel="noopener noreferrer"&gt;others&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In April 2023 I was also reluctant to try ChatGPT, but after reading this twit, I immediately opened it and started testing it. It soon became clear that I was facing something very different from what I had experienced before. I was very impressed and spent hours doing various experiments, including code generation.&lt;/p&gt;

&lt;p&gt;After a day of testing ChatGPT, one thing stuck in my head: if it manages to generate codes so well when it wasn't even created for this purpose, imagine what it must be like to use GitHub Copilot!&lt;/p&gt;

&lt;p&gt;To my joy, I remembered that the company I work for was selecting a group of people to test this tool in the following month, in partnership with Microsoft. I ran and managed to include myself in this team. Couldn't wait to get started! 🎉&lt;/p&gt;

&lt;h1&gt;
  
  
  First impressions
&lt;/h1&gt;

&lt;p&gt;Initially, I didn't know (and, I confess, I still don't know) exactly how to use this technology. As I reported at the beginning of the article, there is no formula, and each person can adapt to their way of working. But it was very impressive. I started small, writing functions in Clojure (backend) and Elm (frontend) in well-defined contexts, and it felt like it could read my mind! I wrote the name of the function and... the implementation appeared! 🧙🪄&lt;/p&gt;

&lt;p&gt;Looked like facing a great revolution and that the way I would program would never be the same. I &lt;strong&gt;felt&lt;/strong&gt; more productive. As if I didn't waste more time with boilerplates and repetitive codes in general. Now I could focus on what matters!&lt;/p&gt;

&lt;p&gt;But little by little I noticed some not-so-cool things, both in the generated code and in my behavior.&lt;/p&gt;

&lt;h1&gt;
  
  
  Confusing and non-standard codes
&lt;/h1&gt;

&lt;p&gt;I used Copilot in a web application that had been in production for over 6 months, with many screens and services that already had a clear design pattern. And while Copilot can adapt, there are limitations. Suddenly I began to notice that the construction of some functions was quite odd, adopting mechanisms that I didn't even know about.&lt;/p&gt;

&lt;p&gt;When I realized that, I tried to see it as a good thing: &lt;em&gt;Wow! I didn't know it was possible to do that. How cool, it's helping me in learning new things!&lt;/em&gt; And it was true. I learned new things because of Copilot. And I could of course reject those suggestions and rewrite them as I wanted.&lt;/p&gt;

&lt;p&gt;On the other hand, it's very easy to get carried away. Gradually I began to feel more and more comfortable in accepting the proposed suggestions. I analyzed the solution, but less judiciously. In some moments it even generated codes that I didn't fully understand. It wasn't necessarily complex but used some language tricks I didn't understand. In some cases, I did some testing (both automated and manual) and it worked. What should I do in these situations? I have a fully working code, but I don't quite understand how it works. I even accepted the solution a few times, saying to myself that I would come back later to study that part (but, of course, I never had the time and inclination to do so).&lt;/p&gt;

&lt;p&gt;At the same time, I felt that the fact that I was able to write code more quickly was worth it.&lt;/p&gt;

&lt;p&gt;Could this be the future? Writing code that we don't quite understand? Perhaps I should create more automated tests and trust that the code is correct as the tests are passing? But wouldn't I use this same technology to write the tests? Do I want to program this way? 🤔&lt;/p&gt;

&lt;p&gt;Many questions started running through my head. Until the worst happened.&lt;/p&gt;

&lt;h1&gt;
  
  
  Oops, I put a bug in production and didn't even notice! 🐛
&lt;/h1&gt;

&lt;p&gt;When I'm programming in Elm, it's not uncommon to start writing not very organized code, to test my ideas. Once I have the screen ready, displaying everything the way I want, I reorganize the code. This usually works great, in part because it's a statically typed language with an amazing compiler. I'm able to change the code and let the compiler guide me, and usually when the code compiles, my application still behaves as expected.&lt;/p&gt;

&lt;p&gt;I'm a big fan of automated tests, but for this part of the application, there were no complex rules. All I had to do was make a REST call to the backend and display some formatted information on the screen. So my test coverage was low.&lt;/p&gt;

&lt;p&gt;And it was during one of these modifications that something strange happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem I was solving
&lt;/h2&gt;

&lt;p&gt;I won't go into too many business details, but I was working on a new functionality for an internal support web page (similar to a dashboard), where it's possible to consult various reports about a given system. This system provides a series of services to other third-party systems, and I needed to expose the usage metrics of these services through a page, with tables, graphs, etc.&lt;/p&gt;

&lt;p&gt;Internally, there is an identification table for these third-party systems, containing (among other things) an identifier (an integer) and a description (a string).&lt;/p&gt;

&lt;p&gt;To do this, I built a new endpoint in the backend that returned a &lt;em&gt;json&lt;/em&gt; containing 2 lists: one of them was a simple key-value, containing the third-party system code and its respective name/description. The other list contained some metrics about the accesses made by these systems, grouped by month.&lt;/p&gt;

&lt;p&gt;In a simplified form, the &lt;em&gt;json&lt;/em&gt; returned was something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"monthYear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1633057200000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;POSIX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;format&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"consumerSystemCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"monthYear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1635735600000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"consumerSystemCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"monthYear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1635735600000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"consumerSystemCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;34032&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"monthYear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1638327600000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"consumerSystemCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;179301&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"consumerSystemCodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"decription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XPTO Systen"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"decription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Foo System"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"decription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Another System"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in this example the first list contains information about systems with identifiers 10 and 11, while the list of &lt;code&gt;consumerSystemCodes&lt;/code&gt; contains identifiers with numbers 10, 11, and &lt;strong&gt;12&lt;/strong&gt;. This is important to understand what went wrong in my code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I solved the problem (without Copilot's help)
&lt;/h2&gt;

&lt;p&gt;I wasn't using Copilot yet while building the first iteration of this screen. It contained a general report, with a summary gathering all systems, followed by a more detailed report, separated by sessions (one for each system).&lt;/p&gt;

&lt;p&gt;To implement this, it is necessary to start from one of two lists: &lt;code&gt;hits&lt;/code&gt; or &lt;code&gt;consumerSystemCodes&lt;/code&gt;. A more distracted person might start from &lt;code&gt;consumerSystemCodes&lt;/code&gt;, since it seems to be easier, after all, one could just make a &lt;em&gt;map&lt;/em&gt; on top of it and generate a session on the screen for each system. Or, even better, could generate some intermediate data structure first, so it can be sorted and transformed however necessary before moving on to the view layer.&lt;/p&gt;

&lt;p&gt;After reflecting a bit, I chose to start with the &lt;code&gt;hits&lt;/code&gt; list, for two main reasons:&lt;/p&gt;

&lt;p&gt;1- There are no restrictions that make it impossible for the &lt;code&gt;hits&lt;/code&gt; list to have an entry with an &lt;code&gt;id&lt;/code&gt; that is not present in the &lt;code&gt;consumerSystemCodes&lt;/code&gt; list. And I wanted to be sure that all entries would be displayed on the screen and, in case this unexpected situation happens, that a new session was created on the screen, with the title "Unknown System (ID: x)" (one session for each unknown identifier).&lt;/p&gt;

&lt;p&gt;2- And the opposite can also occur: the list &lt;code&gt;consumerSystemCodes&lt;/code&gt; may contain systems that do not have any data in the list &lt;code&gt;hits&lt;/code&gt;, so it would be displaying sessions with empty information.&lt;/p&gt;

&lt;p&gt;There are several ways to get around these problems. The way I chose to do it was to start processing with the &lt;code&gt;hits&lt;/code&gt; list.&lt;/p&gt;

&lt;p&gt;So I started with a code that, I confess, was more complex than I initially imagined. Had to create some helper functions to get the needed data, but in the end, it worked fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rearranging with the help of Copilot
&lt;/h2&gt;

&lt;p&gt;I was eager to see the results on the screen and the code reflected that: it was messy and disorganized. But luckily it had been written in Elm! And the compiler was there, ready to help me with the reorganization. And this time I was already using Copilot.&lt;/p&gt;

&lt;p&gt;When I started to change the design of the code, Copilot tried to implement it in the simplest way possible, through the list &lt;code&gt;consumerSystemCodes&lt;/code&gt;. My mind was no longer focused on the potential problems of this path and... I let the Copilot guide me. Suddenly I was smiling, deleting various auxiliary functions that were "no longer needed". And, unfortunately, there were no automated tests to help me with this part of the redesign. Then I opened the system, pointing to my development environment, and... all right! All reports continued to appear as expected.&lt;/p&gt;

&lt;p&gt;I was so excited! I remember texting a colleague to celebrate how Copilot had helped me drastically reduce the complexity of my code! 🥳&lt;/p&gt;

&lt;p&gt;Time to &lt;em&gt;push&lt;/em&gt; and let the &lt;em&gt;pipeline&lt;/em&gt; publish to production.&lt;/p&gt;

&lt;p&gt;As soon as I opened the page in production, I realized that something was wrong. 🪲🐞🪳 Multiple sessions with empty information! In development, this did not happen, since the database content was different. Lucky for me, although I was in the production environment, I hadn't made the link available in the menu yet, so no one else had access to this page and I had time to better analyze what was happening. My first reaction was to create a filter to remove empty entries. But that didn't happen before! What has changed? That's when I realized the source of the problem. And it wasn't just filtering the empty entries, since doing just that wouldn't solve problem 1 that I mentioned above.&lt;/p&gt;

&lt;p&gt;Once again I needed to change the code, this time returning to a logic closer to the original implementation. And once again, Copilot insisted on starting the process through the &lt;code&gt;consumerSystemCodes&lt;/code&gt; list. All autocompletes took me the wrong way and suddenly, I was almost re-implementing the logic in the wrong way again! Even knowing what needed to be done, it was hard not to let Copilot lead me down the wrong path. 🤦&lt;/p&gt;

&lt;p&gt;After some fight, I won! But this battle left a bitter taste in my mouth. And spent hours thinking: &lt;strong&gt;would I have included this bug if not for Copilot?&lt;/strong&gt; Probably not. Could I have avoided this through more automated testing? Probably yes. What if I was doing &lt;em&gt;mob&lt;/em&gt; or &lt;em&gt;pair programming&lt;/em&gt;? Maybe someone would spot the problem. And would an asynchronous code review catch this situation? I think it's unlikely, but maybe.&lt;/p&gt;

&lt;p&gt;But this was just one of the scenarios where something like this happened. There weren't many and this was the most annoying, but they were enough to start causing me some discomfort.&lt;/p&gt;

&lt;h2&gt;
  
  
  More weird code
&lt;/h2&gt;

&lt;p&gt;At some point, I was reviewing the code and noticed something VERY strange: a function was returning an anonymous function, without any reason why. I don't know exactly when that happened, but my hypothesis is that I had created a new function and forgotten to include one of the parameters to do what I needed. Any developer would notice this right away and change the function signature, but Copilot is not able to &lt;strong&gt;change&lt;/strong&gt; the code, it only &lt;strong&gt;suggests new code&lt;/strong&gt;. To solve the problem, I think it created an anonymous function with the missing parameter! The rest of the code was as expected and did the right thing, which is perhaps the reason I accepted the suggestion without realizing the existence of the anonymous function. 😳&lt;/p&gt;

&lt;p&gt;I wondered what it would be like if someone else had encountered this problem in my code! What would they think? That made no sense! Even more so in Elm, where every function has &lt;a href="https://pt.wikipedia.org/wiki/Currying" rel="noopener noreferrer"&gt;currying&lt;/a&gt; by default! If it weren't my code, maybe I'd even be afraid to change it, after all, no human being would write something like that without having a good reason. I could spend hours looking at that lines without realizing why it was returning an anonymous function.&lt;/p&gt;

&lt;h1&gt;
  
  
  Trust or distrust autocomplete?
&lt;/h1&gt;

&lt;p&gt;After a while, I realized that even though I was quite skeptical at first and understood the limitations of an AI-assisted tool, it got it right enough times to slowly gain my trust. And that needed to change.&lt;/p&gt;

&lt;p&gt;Ever since I started working professionally as a software developer, I've been using some kind of code &lt;strong&gt;autocomplete&lt;/strong&gt; tool. In general, simple things like the name of a function or method. One of the advantages of autocompletes in IDEs and code editors is that &lt;strong&gt;I can trust them&lt;/strong&gt;. If my IDE is telling me that this object has a certain method or if a certain module has a certain function, I've learned to believe this information. When I don't remember if the function is called &lt;code&gt;getTaxpayerStatus&lt;/code&gt; or &lt;code&gt;retrieveTaxpayerStatus&lt;/code&gt; and the first option appears in my editor, I &lt;strong&gt;know&lt;/strong&gt; that this is the correct name and &lt;strong&gt;trust&lt;/strong&gt; it.&lt;/p&gt;

&lt;p&gt;But from the moment that my autocomplete starts to &lt;strong&gt;hallucinate&lt;/strong&gt; and &lt;strong&gt;invent&lt;/strong&gt; names for functions or methods, I need to be more cautious. Of course, my IDE (or code editor) autocomplete and Copilot autocomplete are visually quite different, but I need to "turn off" a switch in my brain, which is used to trusting all autocomplete. Now I always have to ask myself: is this based on &lt;strong&gt;facts&lt;/strong&gt; or was this generated by a plugin that is just making things up based on &lt;strong&gt;probability&lt;/strong&gt; and &lt;strong&gt;statistics&lt;/strong&gt;?&lt;/p&gt;

&lt;h1&gt;
  
  
  How to proceed?
&lt;/h1&gt;

&lt;p&gt;Copilot positively surprised me in many ways. I studied AI during &lt;a href="https://dspace.mackenzie.br/handle/10899/24422" rel="noopener noreferrer"&gt;my master's degree&lt;/a&gt; and didn't expect that it would be possible to have such an advanced tool so soon.&lt;/p&gt;

&lt;p&gt;And in the first days it was just joy, but after a month and some non-trivial to detect bugs, using this tool started to generate some stress and anxiety. And something that should have lessened my cognitive load has started to increase it.&lt;/p&gt;

&lt;p&gt;I started to distrust everything that was generated and that pleasant feeling of the first days become less common.&lt;/p&gt;

&lt;p&gt;This doesn't mean that I think GitHub Copilot is bad or that I don't recommend it. On the contrary. It was a really cool experience! And I recommend that every developer try it out and draw their conclusions. I think it's likely that we're moving towards a time when this type of technology will become part of (almost) every developer's day-to-day. Whether this will be good or bad, only time will tell.&lt;/p&gt;

&lt;p&gt;But still, I chose not to use it anymore. At least for a while.&lt;/p&gt;

&lt;p&gt;Although I didn't do any measurements, turning this tool off seems to have slowed me down. Writing a filter, simple parsers, and boilerplates, in general, have become more onerous processes. But this is not necessarily a bad thing. Taking time to reflect on what I'm doing has taken a weight off my shoulders.&lt;/p&gt;

&lt;p&gt;Copilot's slogan is: &lt;em&gt;"Your AI pair programmer"&lt;/em&gt;. And yes, it felt like there was a person programming with me all the time - but an annoying one, who wouldn't shut up for a second. 📣 It was like doing pair programming, but with someone who has no idea what it means to work this way. Who understands absolutely nothing about the problem I want to solve. And when something goes wrong, blames me.&lt;/p&gt;

&lt;p&gt;In the first hours without Copilot I really missed it! I was already used to the idea of ​​typing the name of a function and seeing the code being generated. But soon readjusted to the way I programmed before. And felt more in control. More relaxed.&lt;/p&gt;

&lt;p&gt;I still don't know if (or when) I'll ever use a technology like this again, but for now, I'm fine without it. When I need something very specific, I talk to ChatGPT and that has been enough for me. &lt;/p&gt;




&lt;p&gt;And what about you? Have you tried Copilot yet? What are your thoughts? Leave your comments below!&lt;/p&gt;




&lt;p&gt;Did you like this text? Check out my other articles at: &lt;a href="https://segunda.tech/tags/english" rel="noopener noreferrer"&gt;https://segunda.tech/tags/english&lt;/a&gt; and follow me on &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://staging.bsky.app/profile/segunda.tech" rel="noopener noreferrer"&gt;Blue Sky&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>ai</category>
      <category>coding</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Como foi passar um mês usando o GitHub Copilot e por que pretendo não utilizá-lo (no próxino mês)</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Tue, 13 Jun 2023 11:58:57 +0000</pubDate>
      <link>https://dev.to/marciofrayze/como-foi-passar-um-mes-usando-o-github-copilot-e-por-que-pretendo-nao-utiliza-lo-no-proxino-mes-2nfh</link>
      <guid>https://dev.to/marciofrayze/como-foi-passar-um-mes-usando-o-github-copilot-e-por-que-pretendo-nao-utiliza-lo-no-proxino-mes-2nfh</guid>
      <description>&lt;p&gt;Provavelmente você já deve conhecer o &lt;a href="https://github.com/features/copilot/?ref=heydesigner" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;: uma ferramenta criada pela Microsoft para auxiliar pessoas desenvolvedoras, fornecendo sugestões de código em tempo real. Embora ferramentas como ChatGPT também sejam capazes de gerar código, o GitHub Copilot tem como vantagem ter uma forte integração com o editor de código.&lt;/p&gt;

&lt;p&gt;Existem várias formas de utilizá-lo: você pode escrever uma funcionalidade (até mesmo em português) em formato de comentário e a ferramenta é capaz de gerar uma função, método ou mesmo uma classe inteira completa para contemplar o que descreveu. Ou pode escrever o nome de uma função ou método e esperar que o &lt;em&gt;autocomplete&lt;/em&gt; tente prever o código correspondente. Ou pode ainda utilizá-la apenas como um &lt;em&gt;autocomplete&lt;/em&gt; um pouco mais "inteligente" para partes menores do seu código.&lt;/p&gt;

&lt;p&gt;A primeira forma (utilizando apenas comentários) eu não confio e nunca recomendaria. A segunda, escrevendo apenas o nome da função ou método, costuma funcionar surpreendentemente bem para trechos de código com escopo reduzido e fechado, como por exemplo a criação de uma função que irá receber uma estrutura de dados e fazer alguma operação simples de transformação ou filtro. Já a última forma, como um &lt;em&gt;autocomplete&lt;/em&gt; mais "eficiente", tive resultados mistos. Às vezes acertava em cheio! 🎯 Mas não era incomum precisar de ajustes ou até mesmo apresentar uma solução simplesmente errada. &lt;/p&gt;

&lt;p&gt;Ao longo do mês de maio de 2023, utilizei esta ferramenta para programar em &lt;a href="https://clojure.org" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt; e &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;. Neste artigo conto um pouco sobre o que achei desta experiência.&lt;/p&gt;

&lt;h1&gt;
  
  
  Por que decidi experimentar
&lt;/h1&gt;

&lt;p&gt;Kent Beck postou em abril de 2023 &lt;a href="https://twitter.com/KentBeck/status/1648413998025707520?s=20" rel="noopener noreferrer"&gt;a seguinte mensagem no Twitter&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Estava relutante em experimentar o ChatGPT. Hoje superei essa relutância. Agora entendo por que estava hesitante.&lt;br&gt;
O valor de 90% das minhas habilidades acabou de cair para $0. A importância dos 10% restantes aumentou mil vezes. Preciso me reajustar."&lt;/em&gt; - Kent Beck&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Este twit fez tanto sucesso que ele acabou &lt;a href="https://tidyfirst.substack.com/p/90-of-my-skills-are-now-worth-0" rel="noopener noreferrer"&gt;escrevendo um post&lt;/a&gt; para explicar melhor sua opinião.&lt;/p&gt;

&lt;p&gt;Para quem não conhece, Kent Beck é um dos meus autores de livros técnicos favoritos, tendo escrito livros como &lt;a href="https://www.goodreads.com/book/show/67833.Extreme_Programming_Explained" rel="noopener noreferrer"&gt;eXtreme Programming Explained&lt;/a&gt;, &lt;a href="https://www.goodreads.com/book/show/67839.Planning_Extreme_Programming" rel="noopener noreferrer"&gt;Planning Extreme Programming&lt;/a&gt;, &lt;a href="https://www.goodreads.com/book/show/387190.Test_Driven_Development" rel="noopener noreferrer"&gt;Test-Driven Development: By Example&lt;/a&gt;, entre &lt;a href="https://www.goodreads.com/author/list/25211.Kent_Beck" rel="noopener noreferrer"&gt;outros&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;E em abril de 2023 eu também estava relutante em experimentar o ChatGPT, mas depois de ler este twit, o abri imediatamente e comecei a testá-lo. Em pouco tempo ficou claro que estava diante de algo muito diferente do que já havia experimentado antes. Fiquei muito impressionado e passei horas fazendo diversos experimentos, incluindo geração de códigos.&lt;/p&gt;

&lt;p&gt;Depois de um dia testando o ChatGPT, uma coisa não saía da minha cabeça: se ele consegue gerar códigos tão bem sendo que nem foi criado para esta finalidade, imagine como deve ser usar o GitHub Copilot!&lt;/p&gt;

&lt;p&gt;Para minha alegria, lembrei que a empresa onde trabalho estava iniciando um projeto justamente para testar esta ferramenta, em parceria com a Microsoft. Corri e consegui me incluir no grupo de pessoas que iriam testá-la no mês seguinte. Mal podia esperar para começar! 🎉&lt;/p&gt;

&lt;h1&gt;
  
  
  Primeiras impressões
&lt;/h1&gt;

&lt;p&gt;Inicialmente não sabia (e, confesso, ainda não sei) exatamente como utilizar este tipo de tecnologia. Como relatei no início do artigo, não existe uma fórmula, cada pessoa pode adaptar para sua forma de trabalho. Mas logo fiquei impressionado positivamente. Comecei pequeno, escrevendo funções em Clojure (backend) e Elm (frontend) em contextos bem definidos e parecia que ela podia ler minha mente! Escrevia o nome da função e... aparecia a implementação! 🧙🪄&lt;/p&gt;

&lt;p&gt;Sentia que estava diante de uma grande revolução e que a forma como iria programar nunca mais seria a mesma. Me &lt;strong&gt;sentia&lt;/strong&gt; mais produtivo. Como se não perdesse mais tempo com &lt;em&gt;boilerplates&lt;/em&gt; e códigos repetitivos em geral. Agora poderia me focar no que realmente importa!&lt;/p&gt;

&lt;p&gt;Mas aos poucos fui observando algumas coisas não tão legais assim, tanto no código gerado quanto em meu comportamento.&lt;/p&gt;

&lt;h1&gt;
  
  
  Códigos confusos e despadronizados
&lt;/h1&gt;

&lt;p&gt;Utilizei o Copilot em uma aplicação web que já estava em produção há mais de 6 meses, com muitas telas e serviços já prontos e que já tinha todo um padrão de como o código estava sendo estruturado. E embora o Copilot consiga se adaptar, existem limitações. De repente comecei a observar que a construção de algumas funções estavam bastante fora do padrão, adotando mecanismos que eu nem mesmo conhecia.&lt;/p&gt;

&lt;p&gt;Quando percebi isso, tentei ver pelo lado positivo: &lt;em&gt;nossa! não sabia que dava pra fazer isso. Que legal, além de tudo estou aprendendo coisas novas!&lt;/em&gt; E, por um lado, era verdade. Realmente aprendi coisas novas por conta do Copilot. E claro, bastava não aceitar aquelas sugestões que estivessem fora do padrão e reescrevê-las como eu queria.&lt;/p&gt;

&lt;p&gt;Por outro lado, é muito fácil se deixar levar. Aos poucos comecei a me sentir cada vez mais confortável em aceitar as sugestões propostas. Analisava a solução, mas de forma mais abrangente e menos criteriosa. Em alguns momentos ele chegou a gerar códigos que não entendia perfeitamente. Não eram necessariamente complexos, mas usavam algum artifício da linguagem que desconhecia. Em alguns destes casos, fazia alguns testes (automatizados e manuais) e funcionava. O que devo fazer  nestas situações? Tenho um código funcionando plenamente, mas que não entendo direito como funciona. Cheguei a aceitar a solução algumas vezes, dizendo para mim mesmo que iria voltar depois para estudar melhor aquela funcionalidade da linguagem (mas, claro, nunca tinha tempo e disposição para fazê-lo).&lt;/p&gt;

&lt;p&gt;Ao mesmo tempo sentia que o fato de estar conseguindo escrever códigos mais rapidamente valia muito a pena. &lt;/p&gt;

&lt;p&gt;Seria este o futuro? Escrever códigos que não entendemos direito? Talvez devesse criar mais testes automatizados e confiar que o código está correto, já que os testes estão passando? Mas eu não iria usar esta mesma tecnologia para escrever os testes? Será que eu quero programar desta forma? 🤔&lt;/p&gt;

&lt;p&gt;Muitas perguntas começaram a passar pela minha cabeça. Até que o pior aconteceu.&lt;/p&gt;

&lt;h1&gt;
  
  
  Ops, coloquei um bug em produção e nem percebi! 🐛
&lt;/h1&gt;

&lt;p&gt;Quando estou programando em Elm, não é incomum começar escrevendo códigos não muito organizados, com objetivo de testar minhas ideias. Depois que tenho a tela pronta, já exibindo tudo como quero, reorganizo o código. Normalmente isso funciona muito bem, em parte por ser uma linguagem estaticamente tipada com um compilador incrível. Consigo alterar o código e deixo o compilador me guiar e, em geral, quando o código compila, minha aplicação continua tendo o comportamento esperado.&lt;/p&gt;

&lt;p&gt;Para alguns cenários crio testes automatizados, mas para esta parte da aplicação que estava desenvolvendo, haviam poucas regras complexas. Bastava fazer uma chamada REST para o backend e exibir algumas informações formatadas na tela. Então a minha cobertura de testes estava baixa.&lt;/p&gt;

&lt;p&gt;E foi durante uma dessas alterações que algo estranho aconteceu. &lt;/p&gt;

&lt;h2&gt;
  
  
  Ententendo o problema que estava resolvendo
&lt;/h2&gt;

&lt;p&gt;Não vou entrar em detalhes de negócio, mas estava trabalhando em uma nova funcionalidade de uma página web de apoio (uma espécie de &lt;em&gt;dashboard&lt;/em&gt;), onde é possível consultar vários relatórios sobre um determinado sistema. Este sistema provê uma série de serviços para outros sistemas de terceiros e precisava expor as métricas de uso destes serviços através de uma página, com tabelas, gráficos, etc.&lt;/p&gt;

&lt;p&gt;Internamente existe uma tabela de identificação destes sistemas de terceiros, contendo (entre outras coisas) um identificador (um número inteiro) e uma descrição (uma string). &lt;/p&gt;

&lt;p&gt;Para fazer isso, construi um novo &lt;em&gt;endpoint&lt;/em&gt; no backend que retornava um &lt;em&gt;json&lt;/em&gt; contendo 2 listas: uma delas era bem simples, do tipo chave-valor, contendo o código de sistema consumidor e seu respectivo nome/descrição. &lt;/p&gt;

&lt;p&gt;A outra lista continha algumas métricas sobre os acessos feitos por estes sistemas, com informações agrupadas por mês.&lt;/p&gt;

&lt;p&gt;De forma simplificada, o &lt;em&gt;json&lt;/em&gt; retornado era algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"quantidades"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"anoMes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1633057200000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;formato&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;POSIX&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"codigoSistemaConsumidor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"anoMes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1635735600000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"codigoSistemaConsumidor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"anoMes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1635735600000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"codigoSistemaConsumidor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;34032&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"anoMes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1638327600000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"codigoSistemaConsumidor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;179301&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"codigosSistemasConsumidores"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"descricao"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sistema XPTO"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"descricao"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sistema Foo"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"descricao"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Outro Sistema"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note que neste exemplo a primeira lista contém informações sobre sistemas com identificadores 10 e 11, enquanto a lista de &lt;code&gt;codigosSistemasConsumidores&lt;/code&gt; contém identificadores com os números 10, 11 e &lt;strong&gt;12&lt;/strong&gt;. Isso é importante para entender o que deu errado no meu código.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como resolvi o problema (sem ajuda do Copilot)
&lt;/h2&gt;

&lt;p&gt;Ainda não estava utilizando o Copilot durante a construção da primeira iteração desta tela. Ela continha um relatório geral, com um resumo juntando todos os sistemas, seguida de um relatório mais detalhado, separado por sessões (uma para cada sistema).&lt;/p&gt;

&lt;p&gt;Para implementar isso é necessário partir de uma das duas listas: &lt;code&gt;quantidades&lt;/code&gt; ou &lt;code&gt;codigosSistemasConsumidores&lt;/code&gt;. Uma pessoa mais desatenta talvez começasse a partir da &lt;code&gt;codigosSistemasConsumidores&lt;/code&gt;, já que parece ser mais fácil, afinal seria apenas fazer um &lt;em&gt;map&lt;/em&gt; em cima dela e gerar uma sessão na tela para cada um dos sistemas. Ou, melhor, poderia gerar alguma estrutura de dados intermediária primeiro, para que pudesse ordenar da forma que quisesse e fazer qualquer outro tipo de transformação antes de partir para a camada de visualização.&lt;/p&gt;

&lt;p&gt;Depois de refletir um pouco, optei por iniciar pela lista de  &lt;code&gt;quantidades&lt;/code&gt;, por duas razões principais: &lt;/p&gt;

&lt;p&gt;1- Não existe nenhuma restrição que impossibilite que a lista &lt;code&gt;quantidades&lt;/code&gt; tenha uma entrada com um &lt;code&gt;id&lt;/code&gt; que não esteja presente na lista &lt;code&gt;codigosSistemasConsumidores&lt;/code&gt;. E queria ter absoluta certeza que todas as entradas seriam exibidas na tela e, caso esta situação inesperada aconteça, que fosse criada uma sessão nova na tela, com o título "Sistema Desconhecido (ID: x)" (uma sessão para cada identificador desconhecido).&lt;/p&gt;

&lt;p&gt;2- E o contrário também pode ocorrer: a lista &lt;code&gt;codigosSistemasConsumidores&lt;/code&gt; pode conter sistemas que não tenham nenhum dado na lista &lt;code&gt;quantidades&lt;/code&gt;, então estaria exibindo sessões com informações vazias.&lt;/p&gt;

&lt;p&gt;Existem várias formas de contornar estes problemas. A forma que optei por fazer foi iniciar o processamento pela lista &lt;code&gt;quantidades&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Parti então para o código que, confesso, ficou mais complexo do que imaginei inicialmente. Tive que criar algumas funções auxiliares para obter os dados que precisava, mas no final funcionou adequadamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reorganizando com a ajuda do Copilot
&lt;/h2&gt;

&lt;p&gt;Estava muito ansioso para ver os resultados na tela e o código que escrevi refletiu isso: estava confuso e um pouco desorganizado. Mas felizmente havia escrito em Elm! E o compilador estava ali, pronto para me ajudar na reorganização. E desta vez já estava utilizando o Copilot.&lt;/p&gt;

&lt;p&gt;Quando comecei a alterar o design da parte do código que fazia esta lógica que citei no item anterior, o Copilot tentou realizar o processamento pela forma mais simples possível, através da lista &lt;code&gt;codigosSistemasConsumidores&lt;/code&gt;. Minha mente não estava mais tão ligada nos potenciais problemas deste caminho e... deixei o Copilot me guiar. De repente estava super sorridente, apagando várias funções auxiliares que deixavam de ser necessárias. E, infelizmente, não havia nenhum teste automatizado para me ajudar nesta parte do redesign. Abri então o sistema, apontando para o meu ambiente de desenvolvimento e... tudo certo! Todos os relatórios continuavam aparecendo como esperado. &lt;/p&gt;

&lt;p&gt;Estava muito feliz! Lembro que mandei uma mensagem para um colega, celebrando como o Copilot tinha me ajudado a reduzir drasticamente a complexidade do meu código! 🥳&lt;/p&gt;

&lt;p&gt;Hora de fazer &lt;em&gt;push&lt;/em&gt; e deixar a &lt;em&gt;pipeline&lt;/em&gt; publicar em produção.&lt;/p&gt;

&lt;p&gt;Assim que abri a página em produção, percebi que algo estava errado. 🪲🐞🪳 Várias sessões com informações zeradas! Em desenvolvimento isso não acontecia, já que a massa de dados estava diferente. Para minha sorte, embora estivesse no ambiente de produção, não havia disponibilizado o link no menu de funcionalidades ainda, então ninguém mais tinha acesso à esta página e eu tinha tempo para analisar melhor o que estava acontecendo. Minha primeira reação foi criar um filtro, para retirar as entradas vazias. Mas isso não acontecia antes! O que mudou? Foi quando percebi a origem do problema. E não era apenas filtrar as entradas zeradas, já que fazer apenas isso não resolveria o problema 1 que citei mais acima.&lt;/p&gt;

&lt;p&gt;Mais uma vez precisava alterar o código, desta vez voltando para uma lógica mais próxima à original. E mais uma vez, o Copilot insistia em iniciar o processo através da lista &lt;code&gt;codigosSistemasConsumidores&lt;/code&gt;. Todos os &lt;em&gt;autocompletes&lt;/em&gt; me levavam para o caminho errado e - acredite - quando vi, estava quase implementando novamente a lógica de forma errada! Mesmo sabendo o que precisava ser feito, era difícil não deixar o Copilot me guiar para o caminho errado. 🤦&lt;/p&gt;

&lt;p&gt;Depois de alguma luta, venci! Mas esta batalha deixou um gosto amargo na boca. Passei horas pensando: será que teria incluído este bug se não fosse o Copilot? Provavelmente não. Teria conseguido evitar isso através de mais testes automatizados? Provavelmente sim. E se estivesse fazendo &lt;em&gt;mob&lt;/em&gt; ou &lt;em&gt;pair programming&lt;/em&gt;? Talvez alguém percebesse o problema. E uma revisão de código assíncrona, pegaria esta situação? Acho pouco provável, mas talvez. &lt;/p&gt;

&lt;p&gt;Mas este foi apenas um dos cenários onde algo deste tipo aconteceu. Não foram muitos e este foi o mais chato, mas foram suficientes para começar a me causar certo desconforto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mais códigos estranhos
&lt;/h2&gt;

&lt;p&gt;Em algum momento estava revendo o código e percebi algo MUITO estranho: uma função estava retornando uma função anônima, sem necessidade nenhuma. Não sei exatamente quando aquilo aconteceu, mas minha hipótese é que havia criado uma nova função e esquecido de incluir um dos parâmetros para fazer o que precisava. Qualquer pessoa desenvolvedora perceberia isso na hora e iria alterar a assinatura da função, mas o Copilot não é capaz de &lt;strong&gt;alterar&lt;/strong&gt; o código, apenas &lt;strong&gt;sugerir novos códigos&lt;/strong&gt;. Para resolver o problema da falta de um dos parâmetros, acredito que ele tenha criado uma função anônima com o parâmetro que estava faltando! O restando do código estava como esperado e fazia a coisa certa e, talvez por isso, aceitei a sugestão em algum momento sem perceber a existência da função anônima. 😳&lt;/p&gt;

&lt;p&gt;Fiquei imaginando como seria se outra pessoa tivesse encontrado este problema! O que ela iria pensar? Aquele código não fazia o menor sentido! Ainda mais em Elm, onde toda função possui &lt;a href="https://pt.wikipedia.org/wiki/Currying" rel="noopener noreferrer"&gt;currying&lt;/a&gt; por padrão! Se não fosse meu código, talvez tivesse até receio de alterá-lo, afinal, nenhum ser humano escreveria algo assim sem ter uma boa razão. Poderia passar horas olhando aquele código sem entender o motivo daquilo.&lt;/p&gt;

&lt;h1&gt;
  
  
  Confiar ou desconfiar do &lt;em&gt;autocomplete&lt;/em&gt;?
&lt;/h1&gt;

&lt;p&gt;Em algum momento percebi que, mesmo sendo bastante cético no começo e entendendo as limitações de uma ferramenta de IA, ela acertava quantidade suficiente de vezes para, aos poucos, ganhar minha confiança. E isso precisava mudar.&lt;/p&gt;

&lt;p&gt;Desde que comecei a trabalhar profissionalmente como desenvolvedor de software, uso algum tipo de ferramenta de &lt;em&gt;autocomplete&lt;/em&gt; de código. Em geral, coisas simples, como o nome de uma função ou método. Uma das vantagens dos &lt;em&gt;autocompletes&lt;/em&gt; das IDEs e editores de código é que &lt;strong&gt;eu posso confiar neles&lt;/strong&gt;. Se minha IDE está me dizendo que este objeto tem um determinado método ou se um determinado módulo tem uma certa função, eu aprendi a acreditar nesta informação. Quando não lembro se a função se chama &lt;code&gt;obterSituacaoContribuinte&lt;/code&gt; ou &lt;code&gt;consultarSituacaoContribuinte&lt;/code&gt; e aparece a primeira opção no meu editor, eu &lt;strong&gt;sei&lt;/strong&gt; que este é o nome correto e &lt;strong&gt;confio&lt;/strong&gt; nisso.&lt;/p&gt;

&lt;p&gt;Mas a partir do momento que meu &lt;em&gt;autocomplete&lt;/em&gt; passa a &lt;strong&gt;alucinar&lt;/strong&gt; e &lt;strong&gt;inventar&lt;/strong&gt; nomes para as funções ou métodos, preciso ficar mais atento. Claro que o &lt;em&gt;autocomplete&lt;/em&gt; da minha IDE (ou editor) e o &lt;em&gt;autocomplete&lt;/em&gt; do Copilot são exibidos de forma bastante distintas visualmente, mas preciso "desligar" uma chave do meu cérebro, que já está acostumado a confiar em todo &lt;em&gt;autocomplete&lt;/em&gt;. Agora preciso sempre me questionar: quem está dizendo isso está se baseando em &lt;strong&gt;fatos&lt;/strong&gt; ou isso foi gerado por um &lt;em&gt;plugin&lt;/em&gt; que está apenas inventando coisas baseado em &lt;strong&gt;probabilidade&lt;/strong&gt; e &lt;strong&gt;estatística&lt;/strong&gt;?&lt;/p&gt;

&lt;h1&gt;
  
  
  E agora?
&lt;/h1&gt;

&lt;p&gt;O Copilot me surpreendeu positivamente em muitos aspectos. Estudei sobre IA durante &lt;a href="https://dspace.mackenzie.br/handle/10899/24422" rel="noopener noreferrer"&gt;meu mestrado&lt;/a&gt; e não esperava que fosse possível existir uma ferramenta tão avançada como esta tão cedo.&lt;/p&gt;

&lt;p&gt;E nos primeiro dias foi só alegria, mas depois de um mês e alguns bugs não triviais de detectar, o uso desta ferramenta  começou a me gerar algum estresse e ansiedade. E algo que deveria diminuir minha carga cognitiva, começou a aumentá-la.&lt;/p&gt;

&lt;p&gt;Passei a desconfiar de tudo que era gerado e aquela sensação gostosa dos primeiros dias começou a ficar menos comum.&lt;/p&gt;

&lt;p&gt;Isso não significa que considere o GitHub Copilot ruim ou que não o recomende. Pelo contrário. Foi uma experiência muito legal! E recomendo que toda pessoa desenvolvedora experimente e tire suas próprias conclusões. Acho provável que estejamos caminhando para um momento em que este tipo de tecnologia vai passar a fazer parte do dia a dia de (quase) toda pessoa desenvolvedora. Se isso vai ser bom ou ruim, só o tempo dirá.&lt;/p&gt;

&lt;p&gt;Mas, ainda assim, optei por não utilizá-la mais. Pelo menos por enquanto. &lt;/p&gt;

&lt;p&gt;Embora não tenha feito nenhum tipo de medição, desligar esta ferramenta aparentemente diminuiu a minha velocidade. Escrever um filtro, &lt;em&gt;parsing&lt;/em&gt; e &lt;em&gt;boilerplaites&lt;/em&gt; em geral tornaram-se processos mais onerosos. Mas isso não é algo necessariamente ruim. Ter um tempo para refletir sobre o que estou fazendo tirou um peso das minhas costas. &lt;/p&gt;

&lt;p&gt;O slogan do Copilot é: &lt;em&gt;"Your AI pair programmer"&lt;/em&gt;, que poderia traduzir em algo como "seu programador em par com IA". E realmente sentia como se estivesse uma pessoa programando comigo o tempo todo - mas uma pessoa chata, que não calava a boca um segundo. 📣 Era como fazer &lt;em&gt;pair programming&lt;/em&gt;, mas com alguém que não faz ideia do que significa trabalhar de forma pareada. Que não entende absolutamente nada sobre o problema que quero resolver. E que quando algo dá errado, coloca toda culpa em mim.&lt;/p&gt;

&lt;p&gt;Nas primeiras horas sem Copilot senti muita falta! Já estava acostumado com a ideia de digitar o nome de uma função e ver o código sendo gerado. Mas logo me readaptei à forma que programava antes. E me senti mais no controle. Mais relaxado.&lt;/p&gt;

&lt;p&gt;Ainda não sei se (ou quando) vou voltar a utilizar uma tecnologia como esta, mas por enquanto, estou bem sem ela. Quando preciso de algo muito específico, converso com o ChatGPT e isso tem sido suficiente para mim.&lt;/p&gt;




&lt;p&gt;E você? Como já experimentou o Copilot? O que tem achado? Deixe sua opinião nos comentários.&lt;/p&gt;




&lt;p&gt;Gostou deste texto? Conheça meus outros artigos, podcasts e vídeos acessando: &lt;a href="https://segunda.tech" rel="noopener noreferrer"&gt;https://segunda.tech&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;E se quiser, me segue lá no &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt; e &lt;a href="https://staging.bsky.app/profile/segunda.tech" rel="noopener noreferrer"&gt;blue sky&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>ai</category>
      <category>coding</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why I decided to learn (and teach) Clojure</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Mon, 20 Mar 2023 13:06:24 +0000</pubDate>
      <link>https://dev.to/marciofrayze/why-i-decided-to-learn-and-teach-clojure-567f</link>
      <guid>https://dev.to/marciofrayze/why-i-decided-to-learn-and-teach-clojure-567f</guid>
      <description>&lt;p&gt;In 2017 I started to learn more about the universe of Functional Programming. This paradigm was gaining traction and most object-oriented programming languages ​​were adding more and more features inspired by this paradigm, including the language that I used the most: Java.&lt;/p&gt;

&lt;p&gt;After the JDK 8 release in March 2014, it became common to hear Java developers using terms like: functional programming, &lt;em&gt;streams&lt;/em&gt;, &lt;em&gt;optional&lt;/em&gt;, &lt;em&gt;map&lt;/em&gt;, &lt;em&gt;flat map&lt;/em&gt;, etc. But many people around me still ignored these new features and, I confess, it took me a while to adopt them. The ideas sounded very interesting, but putting them into practice turned out to be more difficult than I expected.&lt;/p&gt;

&lt;p&gt;After much trial and error, I decided to dig deeper into the concepts. The book &lt;a href="https://www.oreilly.com/library/view/functional-thinking/9781449365509/" rel="noopener noreferrer"&gt;Functional Thinking&lt;/a&gt; helped me take my first steps in the right direction.&lt;/p&gt;

&lt;p&gt;In parallel I decided to learn a functional-first programming language instead of trying to partially apply the functional paradigm in an object-oriented language. After doing a lot of research, I chose to learn &lt;a href="https://elm-lang.org" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;. The fact that it is a pure and immutable functional language caught my attention. Also, it is focused on &lt;em&gt;webapps&lt;/em&gt; development and, until then, I hadn't found any solution for developing web pages that I liked.&lt;/p&gt;

&lt;p&gt;After going through the whole &lt;a href="https://guide.elm-lang.org" rel="noopener noreferrer"&gt;Introductory Guide to the Elm Language&lt;/a&gt; and reading the &lt;a href="https://www.manning.com/books/elm-%20in-action" rel="noopener noreferrer"&gt;Elm in Action&lt;/a&gt; book, I already felt quite comfortable developing &lt;em&gt;webapps&lt;/em&gt; in this paradigm. I liked Elm so much that I started a project to teach programming to beginners using this language and made the first classes available on the website &lt;a href="https://elm.dev.br" rel="noopener noreferrer"&gt;elm.dev.br&lt;/a&gt; (in Brazilian Portuguese).&lt;/p&gt;

&lt;p&gt;But there was a serious problem that I still had to face: Elm is a language designed for &lt;em&gt;webapps&lt;/em&gt; development and works very well for that, but I was looking for a general purpose solution, that could also be used in &lt;em&gt;backends&lt;/em&gt; development. So I started hunting for another language again.&lt;/p&gt;

&lt;p&gt;Elm is a statically typed language inspired by &lt;a href="https://www.haskell.org" rel="noopener noreferrer"&gt;Haskell&lt;/a&gt;. The natural step would be to use Elm on the &lt;em&gt;frontend&lt;/em&gt; and Haskell on the &lt;em&gt;backend&lt;/em&gt;. And that's what I tried to do. I read with some difficulty the &lt;em&gt;Learn You a Haskell for Great Good!&lt;/em&gt; book (available for free &lt;a href="http://learnyouahaskell.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;) and learned a lot of cool stuff. But creating a complete &lt;em&gt;backend&lt;/em&gt; using Haskell proved to be more than I could chew. So I decided to look for alternatives...&lt;/p&gt;

&lt;p&gt;During this whole process the word &lt;a href="https://pt.wikipedia.org/wiki/Lisp" rel="noopener noreferrer"&gt;Lisp&lt;/a&gt; kept popping into my head! From time to time I would come across a video of someone influential in the community talking about it (like &lt;a href="https://www.youtube.com/watch?v=Uooh0Y9fC_M#t=4876ab_channel=IGN" rel="noopener noreferrer"&gt;this video&lt;/a&gt; or &lt;a href="https://twitter.com/ID_AA_Carmack/status/577877590070919168" rel="noopener noreferrer"&gt;this twit&lt;/a&gt; by &lt;a href="https://pt.wikipedia.org/wiki/John_Carmack" rel="noopener noreferrer"&gt;John Carmack&lt;/a&gt;, founder of &lt;em&gt;id Software&lt;/em&gt;). It felt mystical. And the fact that &lt;a href="https://building.nubank.com.br/working-with-clojure-at-nubank" rel="noopener noreferrer"&gt;Nubank adopted Clojure&lt;/a&gt; brought a very real and pragmatic case study of the use of a Lisp dialect here in Brazil.&lt;/p&gt;

&lt;p&gt;Until then I was postponing studying it because I was prioritizing statically typed languages ​​and the most famous dialects of Lisp are dynamic languages. But in early 2021 I finally decided to give it a chance. I chose the language &lt;a href="https://clojure.org|Clojure" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt; and started reading the &lt;a href="https://pragprog.com/titles/roclojure/getting-clojure" rel="noopener noreferrer"&gt;Getting Clojure&lt;/a&gt; book. Unlike my Haskell studies, I managed to read this book in just a few days! At the same time, I started taking Clojure classes at &lt;a href="https://www.alura.com.br/formacao-clojure" rel="noopener noreferrer"&gt;Alura&lt;/a&gt; (a popular online programming school in Brazil), which helped me to see how to program in this language in hands-on. It was a good combination: in the book I learned the concepts of the language more deeply and in the course I reviewed these concepts and learned the more practical parts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clojure's key features
&lt;/h2&gt;

&lt;p&gt;Lisp is not a programming language, but a family of languages ​​with many &lt;em&gt;dialects&lt;/em&gt;. The most famous dialects include &lt;a href="https://lisp-lang.org" rel="noopener noreferrer"&gt;Common Lisp&lt;/a&gt;, &lt;a href="https://clojure.org" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;, &lt;a href="https://groups.csail.mit.edu%20/mac/projects/scheme" rel="noopener noreferrer"&gt;Scheme&lt;/a&gt; and &lt;a href="https://racket-lang.org" rel="noopener noreferrer"&gt;Racket&lt;/a&gt;. So after deciding that I was going to learn Lisp, I had to choose one of its dialects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clojure.org" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt; stood out to me for two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it uses the Java Virtual Machine, enabling interoperability with Java applications (which, as I said at the beginning of the article, is the language I usually use in the &lt;em&gt;backend&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;it predominantly uses the functional paradigm. Some Lisp dialects (like Common Lisp) are multiparadigm, but as my intention was to go deeper into the universe of functional programming, it made sense to adopt a dialect that was &lt;em&gt;functional first&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The experience of programming in Clojure was quite liberating. Practice &lt;a href="https://pt.wikipedia.org/wiki/Test-driven_development" rel="noopener noreferrer"&gt;TDD&lt;/a&gt; together with &lt;a href="https://practical.li/clojure/repl-driven-devlopment.html" rel="noopener noreferrer"&gt;REPL Driven Development&lt;/a&gt; (technique quite widespread inside the Clojure community) makes the &lt;em&gt;feedback&lt;/em&gt; loop very fast. The fact that Clojure is a dynamic language also contributes to that.&lt;/p&gt;

&lt;p&gt;Another characteristic of Clojure is that it is an &lt;em&gt;impure&lt;/em&gt; language, that is, we can have &lt;em&gt;side effects&lt;/em&gt; at any time. The main advantage of this is that it makes the language easier to learn (although it brings with it a host of other problems that don't happen in purer languages ​​like Elm or Haskell).&lt;/p&gt;

&lt;p&gt;But although it is an impure language, it encourages a series of good practices that significantly reduces the potential problems of this approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with Clojure
&lt;/h2&gt;

&lt;p&gt;Clojure might be intimidating at first, but after a few hours you get used to it's syntax and it's actually quite easy to learn. That's why I also chose this language to share with other developers the basic fundamentals of &lt;em&gt;functional programming&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If books are your thing, I recommend starting with &lt;a href="https://pragprog.com/titles/roclojure/getting-clojure" rel="noopener noreferrer"&gt;Getting Clojure&lt;/a&gt;, which as I said earlier, is a great way to understand the basic principles behind Clojure. But if you are looking for a free option, you may start with the online version of the &lt;a href="https://www.braveclojure.com" rel="noopener noreferrer"&gt;Clojure for Brave and True&lt;/a&gt; book. Another option more focused on the foundations of the paradigm and that addresses languages ​​other than Clojure is the book &lt;a href="https://www.oreilly.com/library/view/functional-thinking/9781449365509/" rel="noopener noreferrer"&gt;Functional Thinking&lt;/a&gt;, by Neal Ford.&lt;/p&gt;

&lt;p&gt;I created a &lt;a href="https://segundatech.teachable.com" rel="noopener noreferrer"&gt;10 hours course on Introduction to Functional Programming with Clojure&lt;/a&gt; with optional payment (yes, you can enroll for free if you want to!). But right now it's only available in my native language: Brazilian Portuguese. 😉&lt;/p&gt;

&lt;p&gt;And you, what is your favorite paradigm? Have you tried programming using the functional paradigm? What were your main difficulties? Share your experiences in the comments!&lt;/p&gt;




&lt;p&gt;Did you like this text? Checkout my other articles at: &lt;a href="https://segunda.tech/tags/english" rel="noopener noreferrer"&gt;https://segunda.tech/tags/english&lt;/a&gt; and follow me on &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>Fantasy Consoles: What would the retro console of your dreams look like?</title>
      <dc:creator>Marcio Frayze</dc:creator>
      <pubDate>Thu, 16 Mar 2023 16:31:33 +0000</pubDate>
      <link>https://dev.to/marciofrayze/fantasy-consoles-what-would-the-retro-console-of-your-dreams-look-like-3p54</link>
      <guid>https://dev.to/marciofrayze/fantasy-consoles-what-would-the-retro-console-of-your-dreams-look-like-3p54</guid>
      <description>&lt;p&gt;&lt;em&gt;A Brazilian Portuguese version is available &lt;a href="https://dev.to/marciofrayze/fantasy-consoles-como-seria-o-console-retro-dos-seus-sonhos-1hc3"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In the mid-1990s I had my first contact with a computer: a &lt;a href="https://en.wikipedia.org/wiki/Gradiente_Expert" rel="noopener noreferrer"&gt;Gradient Expert&lt;/a&gt; (&lt;a href="https://en.wikipedia.org/wiki/MSX" rel="noopener noreferrer"&gt;MSX&lt;/a&gt; 1) of my older brothers. At the time it was already an old computer but I had a lot of fun. And it was in this computer that I wrote my first lines of code, using the BASIC language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F891n93ixks0j2idfxtlt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F891n93ixks0j2idfxtlt.gif" alt="Animation showing the startup of MSX and creating a very simple program" width="436" height="318"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51n2rmk3o40c8qyeqqvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51n2rmk3o40c8qyeqqvq.png" alt="Photo of a Gradient Expert computer, released in 1985" width="420" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few years later I had access to a 486DX2-66Mhz running the Microsoft DOS operating system and Windows 3.11. But I never had that same MSX's era feeling again. Pressing the power button and in a few seconds being in a terminal, typing lines of code right away, has become somewhat nostalgic. After that, on all computers had to wait several minutes, use the mouse, click icons, wait several more minutes... 😮‍💨&lt;/p&gt;

&lt;p&gt;With the evolution of technology it was natural to expect the experience to improve, but it was not what I &lt;strong&gt;felt&lt;/strong&gt;. Of course the experience has somehow improved: more memory, better graphics, disk space, dozens of times faster processors... but the &lt;strong&gt;feeling&lt;/strong&gt; was that everything got worse, that before everything was more fun. Typing &lt;em&gt;Run&lt;/em&gt; and pressing &lt;em&gt;Enter&lt;/em&gt; was much nicer than clicking an icon on the screen. But you can't slow progress. At some point I surrendered to Windows and it's mouse (after all I also wanted to play the latest game releases!).&lt;/p&gt;

&lt;p&gt;Perhaps because of this nostalgic feeling, when I first opened a &lt;em&gt;Fantasy Console&lt;/em&gt; I was very excited! The terminal was similar to the one I was used to as a teenager. The games too: simple sprites, without too much visual and sound effects. It was like using a computer from the 80s again, but in a thousand times more organized, practical and fun environment. This was my first sensation when using &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvo07e38cedusxycg4dy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvo07e38cedusxycg4dy.gif" alt="Animation showing loading and running a sample created using PICO-8" width="343" height="338"&gt;&lt;/a&gt; &lt;br&gt;
In the animation above you can see PICO-8 running with its terminal screens and code, sprites, maps, sound effects and music editors. Everything you need to create your games with a retro style! 🕹️&lt;/p&gt;

&lt;h2&gt;
  
  
  Definition
&lt;/h2&gt;

&lt;p&gt;The term &lt;em&gt;Fantasy Console&lt;/em&gt; was coined by Joseph White, creator of the first console of its kind, &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt;. According to the &lt;a href="https://www.lexaloffle.com/pico-8.php?page=faq" rel="noopener noreferrer"&gt;PICO-8 FAQ&lt;/a&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A fantasy console is like a regular console, but without the inconvenience of actual hardware. PICO-8 has everything else that makes a console a console: machine specifications and display format, development tools, design culture, distribution platform, community and playership. It is similar to a retro game emulator, but for a machine that never existed. PICO-8's specifications and ecosystem are instead designed from scratch to produce something that has its own identity and feels real. Instead of physical cartridges, programs made for PICO-8 are distributed on .png images that look like cartridges, complete with labels and a fixed 32k data capacity."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;p&gt;The main advantages of programming for a console that never existed is that real consoles like Atari 2600, NES, Master System and others were created in order to be as powerful as possible, spending the minimum required with &lt;em&gt;hardware&lt;/em&gt;. This makes programming for these platforms not to be very beginner friendly, after all, this was never the intention. The focus was on major studios, with many professional game developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fantasy consoles&lt;/strong&gt; can afford not to worry about it so much. They do not need to be as fast as possible or worry about the &lt;em&gt;hardware&lt;/em&gt; production. Everything revolves around &lt;em&gt;softwares&lt;/em&gt;. This makes the user experience much more enjoyable and a great way for beginners to enter the game development world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Every &lt;strong&gt;fantasy console&lt;/strong&gt; imposes some artificial technical limitations. You will have to work with a lower video resolution, limited sound effects and music creation tools, reduced color palette, etc. At first this may sound like something very bad and it seems that it will be more difficult to program like this, but in practice these restrictions end up being very liberating and become one of the main attractions.&lt;/p&gt;

&lt;p&gt;The goal is retro game development and the imposition of these limitations helps to maintain our focus. Besides, they force us to use more of our imagination. The end result is usually simple and fun to play games.&lt;/p&gt;

&lt;p&gt;Each &lt;strong&gt;fancy console&lt;/strong&gt; will impose its own restrictions. Games created with the PICO-8, for example, will have the following restrictions: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;128x128 pixel screen; &lt;/li&gt;
&lt;li&gt;Palette of 16 colors; &lt;/li&gt;
&lt;li&gt;32Kb as the maximum "cartridge" size;&lt;/li&gt;
&lt;li&gt;Four sound tracks; &lt;/li&gt;
&lt;li&gt;Lua programming language; &lt;/li&gt;
&lt;li&gt;256 8x8 &lt;em&gt;Sprites&lt;/em&gt;; &lt;/li&gt;
&lt;li&gt;Map with 182x32 &lt;em&gt;tiles&lt;/em&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are other consoles that are even more limited than that! But also some way more flexible and powerful (and consequently more complex) systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some games developed for fantasy consoles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Celeste Classic
&lt;/h3&gt;

&lt;p&gt;You may have heard of a game called &lt;a href="http://www.celestegame.com" rel="noopener noreferrer"&gt;Celeste&lt;/a&gt;, available for Nintendo Switch, Playstation 4 and Xbox One. What you may not know is that it was based on an homonymous game (now known as Celeste Classic) developed by the same team. This original version was developed in 4 days in a &lt;em&gt;game jam&lt;/em&gt;, using &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rt95drefvb84v4dnt9k.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rt95drefvb84v4dnt9k.gif" alt="Animation showing Celeste Classic game" width="355" height="354"&gt;&lt;/a&gt;&lt;br&gt;
You can play Celeste Classic directly in your browser by going to &lt;a href="https://www.lexaloffle.com/bbs/?tid=2145" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Celeste Classic 2
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhf8267cy1y1vssgdmwq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhf8267cy1y1vssgdmwq.gif" alt="Animation showing Celeste Classic 2 game" width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Celeste for Switch, PlayStation 4 and Xbox One don't have a sequel and the authors have said it probably never will. But to our joy, Celeste Classic has one! With new dynamics but the same high degree of challenge. You can play Celeste Classic 2 directly in your browser by visiting &lt;a href="https://mattmakesgames.itch.io/celeste-classic-2" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  PakPok
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36dwhepo80c5x8ik64s2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36dwhepo80c5x8ik64s2.gif" alt="Animation showing the PakPok game" width="360" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you like platform games that mix puzzles and precision movements to advance to the next screen, you'll probably like &lt;a href="https://www.lexaloffle.com/bbs/?pid=67558#p" rel="noopener noreferrer"&gt;PakPok&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  NanoMan
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijm0dhetta1sns9h534a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijm0dhetta1sns9h534a.gif" alt="Animation showing the NanoMan game" width="360" height="361"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Remember MegaMan (RockMan in Japan) from the NES console? I loved this game! And I love this version of NanoMan, inspired by this game. Another really cool game made using PICO-8. You can play it in the browser in &lt;a href="https://www.lexaloffle.com/bbs/?tid=29017" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fetch Quest
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufcvyomye2fnb8zvzcju.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufcvyomye2fnb8zvzcju.gif" alt="Animation showing the Fetch Quest game" width="410" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lumpytouch.itch.io/fetch-quest" rel="noopener noreferrer"&gt;Fetch Quest&lt;/a&gt; is another platform game where you also have to solve puzzles, but this time you're in the role of a dog!&lt;/p&gt;

&lt;p&gt;This game was created using the &lt;a href="https://tic80.com" rel="noopener noreferrer"&gt;TIC-80&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everdawn
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg2cnsnkx7if6ol3egko7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg2cnsnkx7if6ol3egko7.gif" alt="Animation showing the Everdawn game" width="420" height="246"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;While fantasy consoles are great for 2D platform creations, there are a myriad of other games of the most diverse styles! Among them is &lt;a href="https://lucentbeam.itch.io/everdawn" rel="noopener noreferrer"&gt;Everdawn&lt;/a&gt;. An RPG also created using the &lt;a href="https://tic80.com" rel="noopener noreferrer"&gt;TIC-80&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  And many others!
&lt;/h3&gt;

&lt;p&gt;You can find more games created using PICO-8 &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;on this page&lt;/a&gt; and others created for TIC-80 &lt;a href="https://tic80.com" rel="noopener noreferrer"&gt;on this&lt;/a&gt; and &lt;a href="https://itch.io/c/110298/games-made-with-tic-80" rel="noopener noreferrer"&gt;on this other&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming language and development environment
&lt;/h2&gt;

&lt;p&gt;Each &lt;strong&gt;fantasy console&lt;/strong&gt; will have its own development tools. Some will allow you to use several different languages and allow you to program in external editors, even containing &lt;em&gt;plugins&lt;/em&gt; to program using the famous &lt;em&gt;VSCode&lt;/em&gt;.&lt;br&gt;
Others will require you to program in a more traditional and limited way, forcing the use of only the editing and programming tools built into the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which fantasy console to start with?
&lt;/h2&gt;

&lt;p&gt;There is a huge amount of fantasy consoles (and computers). A list with a summary of the characteristics of each one is available &lt;a href="https://paladin-t.github.io/fantasy" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You have options that will allow you to program in JavaScript, Lua, BASIC, Python, among many others. Some consoles will restrict you a lot, others will leave you very free.&lt;/p&gt;

&lt;p&gt;Because there are so many options, some similar and some very different, it is very difficult to choose which one to start with. So I'll leave here two suggestions for you: one that needs a license to use and one free.&lt;/p&gt;

&lt;h3&gt;
  
  
  PICO-8
&lt;/h3&gt;

&lt;p&gt;My favorite &lt;strong&gt;fantasy console&lt;/strong&gt; is still &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt;. This was the first project of its kind and the author managed to keep all the initial philosophy. It's not the most powerful but that's exactly the beauty of this project!&lt;/p&gt;

&lt;p&gt;To develop your games you will use the famous &lt;a href="https://www.lua.org" rel="noopener noreferrer"&gt;Lua programming language&lt;/a&gt; and you will have at your disposal a very simple editor to use. In it you'll create your codes, your &lt;em&gt;sprites&lt;/em&gt;, maps, sound effects and music: everything already included, very intuitive and easy to use.&lt;/p&gt;

&lt;p&gt;But this is proprietary software. At the time of writing this article, the license costs $14.99. And you can choose to pay $5 more and also receive a copy of the &lt;em&gt;alpha&lt;/em&gt; version of &lt;a href="https://www.lexaloffle.com/voxatron.php" rel="noopener noreferrer"&gt;Voxatron&lt;/a&gt;, a &lt;strong&gt;fantasy console&lt;/strong&gt; for 3D gaming that it is still being developed by the same team as PICO-8.&lt;/p&gt;

&lt;p&gt;While there are rumors that they are working on a mobile version, PICO-8 is currently only available on major &lt;em&gt;desktop&lt;/em&gt; platforms (Windows, Mac and Linux).&lt;/p&gt;

&lt;h3&gt;
  
  
  TIC-80
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://tic80.com" rel="noopener noreferrer"&gt;TIC-80&lt;/a&gt; is another popular &lt;strong&gt;fantasy console&lt;/strong&gt;. It is more versatile than the PIC-8 and in addition to supporting the main &lt;em&gt;desktop&lt;/em&gt; platforms, it also has &lt;a href="https://play.google.com/store/apps/details?id=com.nesbox.tic" rel="noopener noreferrer"&gt;an Android version&lt;/a&gt;. That's right! You can run and create your games on this &lt;strong&gt;fantasy console&lt;/strong&gt; right from your mobile phone!&lt;/p&gt;

&lt;p&gt;Another very positive point of TIC-80 is that it is &lt;em&gt;open-source&lt;/em&gt; (source code available &lt;a href="https://github.com/nesbox/TIC-80" rel="noopener noreferrer"&gt;in this github repository&lt;/a&gt;) and that it can be downloaded for free.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftic80.com%2Fimg%2Fdemo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftic80.com%2Fimg%2Fdemo.gif" alt="TIC-80 demo" width="" height=""&gt;&lt;/a&gt; The animation above was taken from the website &lt;a href="https://tic80.com" rel="noopener noreferrer"&gt;tic80.com&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;And you? Have you ever developed games with a retro style? What are your favorite tools? Tell me about your experience in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8 Official Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tic80.com" rel="noopener noreferrer"&gt;TIC-80 Official Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Fantasy_video_game_console" rel="noopener noreferrer"&gt;&lt;em&gt;Fantasy video game console&lt;/em&gt; page on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/lexaloffle" rel="noopener noreferrer"&gt;PICO-8 Official Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Celeste_(video_game)" rel="noopener noreferrer"&gt;Celeste game page on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://itch.io/c/110298/games-made-with-tic-80" rel="noopener noreferrer"&gt;Games made with TIC-80&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.lexaloffle.com/voxatron.php" rel="noopener noreferrer"&gt;Voxatron, a fantasy console for 3D games&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://paladin-t.github.io/fantasy" rel="noopener noreferrer"&gt;List containing various fantasy consoles and computers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Did you like this text? Checkout my other articles at: &lt;a href="https://segunda.tech/tags/english" rel="noopener noreferrer"&gt;https://segunda.tech/tags/english&lt;/a&gt; and follow me on &lt;a href="https://twitter.com/marciofrayze" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>pico8</category>
      <category>tic80</category>
      <category>fantasyconsole</category>
      <category>gamedev</category>
    </item>
  </channel>
</rss>
