<?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: Eduardo Teixeira</title>
    <description>The latest articles on DEV Community by Eduardo Teixeira (@dunirvana).</description>
    <link>https://dev.to/dunirvana</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F241501%2Ff66f6684-1499-4b98-9828-bdbfba7238e8.jpeg</url>
      <title>DEV Community: Eduardo Teixeira</title>
      <link>https://dev.to/dunirvana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dunirvana"/>
    <language>en</language>
    <item>
      <title>Black October: AI sped up the hunt for vulnerabilities, and the bill came due</title>
      <dc:creator>Eduardo Teixeira</dc:creator>
      <pubDate>Sat, 07 Nov 2026 15:59:01 +0000</pubDate>
      <link>https://dev.to/dunirvana/black-october-ai-sped-up-the-hunt-for-vulnerabilities-and-the-bill-came-due-42pj</link>
      <guid>https://dev.to/dunirvana/black-october-ai-sped-up-the-hunt-for-vulnerabilities-and-the-bill-came-due-42pj</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published in Portuguese on my blog: &lt;a href="https://programero.blogspot.com/2026/11/black-october-ia-e-seguranca.html" rel="noopener noreferrer"&gt;Black October: a IA acelerou a caça às falhas, e a conta chegou&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;October is officially Cybersecurity Awareness Month. In 2026 it earned a much less friendly nickname: &lt;strong&gt;Black October&lt;/strong&gt;. In just a few days we saw a critical PHP flaw discovered with the help of AI, a certificate authority leaving the market because of private keys you could practically guess, and a popular AI library distributing malware through PyPI. If you work with software and didn't have to update anything in the last few weeks, you were either very lucky or didn't look closely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;The loudest episode was &lt;strong&gt;PHP2Shell&lt;/strong&gt;. Researchers at Wiz, with support from OpenAI and Calif, found memory-safety flaws in the PHP core, tied to how the language handles fatal errors, mainly memory exhaustion. A failing request can leave corrupted internal state behind, which another request later reuses. The result is unauthenticated remote code execution, with severity scores up to 9.2. The most striking detail: the problem had been there for more than a decade and affected practically every version since PHP 5.4.&lt;/p&gt;

&lt;p&gt;According to Wiz itself, frontier AI models took part in the discovery, in building the exploits and in validating the patches. The first flaw was found on August 19; within two days there was confirmed remote execution on Drupal and WordPress. PHP shipped the fixes (8.2.35, 8.3.36, 8.4.27 and 8.5.12) on October 21, and the NSA went as far as recommending updating immediately or taking systems offline until you could.&lt;/p&gt;

&lt;p&gt;Almost at the same time came the &lt;strong&gt;eMudhra&lt;/strong&gt; case, an Indian certificate authority. A researcher found that eight private keys for intermediate certificates had values smaller than 256. Yes: keys that should be gigantic random numbers could be recovered almost instantly. Chrome and Firefox blocked the intermediates within hours, Mozilla stopped trusting the affected root, and the company announced it would exit the global TLS certificate business. About 30,000 certificates had to be replaced.&lt;/p&gt;

&lt;p&gt;To close out the week, &lt;strong&gt;LiteLLM&lt;/strong&gt;, a library widely used to talk to multiple language model providers, had its release pipeline compromised. For a few hours on the 21st, version 1.107.0 on PyPI and images on Docker Hub carried a credential stealer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters if you work in tech
&lt;/h2&gt;

&lt;p&gt;None of these cases is new in shape. Old bugs in popular languages, CAs with poor processes and supply chain attacks have all happened before. What changed is the pace. In August, Microsoft's Patch Tuesday fixed 419 vulnerabilities, about five times the volume of a typical month before this wave; in October, the security press counted more than 1,400. Finding flaws got cheaper, and that holds for defenders and attackers alike.&lt;/p&gt;

&lt;p&gt;In practice, a few things become obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Updating is no longer a "when I get around to it" task.&lt;/strong&gt; If the window between disclosure and exploit keeps shrinking, the patch process has to be fast and, ideally, automated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory is security.&lt;/strong&gt; If you don't know which versions of PHP, Node or Python libraries you run in production, you lose days just figuring out whether you were affected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pinning versions and verifying package origin matters.&lt;/strong&gt; The LiteLLM case shows that an uncritical automatic update can be the very entry point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic certificate renewal isn't the end of the story.&lt;/strong&gt; Chrome warned that common ACME clients may not replace certificates outside the renewal window without ARI support or manual intervention.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My take
&lt;/h2&gt;

&lt;p&gt;A lot of people are treating Black October as proof that AI is going to "break the internet". I see it differently. The PHP flaws had existed for more than ten years; AI didn't create them, it just found them. This is collective technical debt being collected all at once, and it's better for it to be collected by researchers doing coordinated disclosure than by someone working in silence.&lt;/p&gt;

&lt;p&gt;The problem is that the capacity to fix doesn't scale at the same pace as the capacity to find. Open source projects maintained by a handful of people, companies with legacy systems nobody dares to touch, and teams that treat updates as a risk rather than as protection will feel it first. The eMudhra case, by the way, didn't even involve AI: it was a basic process failure, the kind that only shows up when someone finally decides to look.&lt;/p&gt;

&lt;p&gt;For developers, the lesson is less glamorous than it seems: keep dependencies up to date, know what runs in production, have a reliable deploy pipeline and enough tests to update without fear. None of this is new. The difference is that now the bill arrives faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.wiz.io/blog/php2shell-php-rce" rel="noopener noreferrer"&gt;Wiz: PHP2Shell: AI uncovers critical RCE vulnerabilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bleepingcomputer.com/news/security/php-ships-emergency-patches-for-critical-php2shell-flaws" rel="noopener noreferrer"&gt;BleepingComputer: PHP ships emergency patches for critical PHP2Shell flaws&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcrunch.com/2026/10/21/the-internet-is-having-a-very-bad-cybersecurity-day/" rel="noopener noreferrer"&gt;TechCrunch: The internet is having a very bad cybersecurity day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thehackernews.com/2026/10/emudhra-to-exit-global-ssltls-business.html" rel="noopener noreferrer"&gt;The Hacker News: eMudhra to exit global SSL/TLS business&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.litellm.ai/blog/security-incident-oct-21-2026" rel="noopener noreferrer"&gt;LiteLLM: Security incident, Oct 21 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://therecord.media/microsoft-massive-patch-tuesday-releases-continue-ai" rel="noopener noreferrer"&gt;The Record: Microsoft's massive Patch Tuesday releases continue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bleepingcomputer.com/news/microsoft/microsoft-october-2026-patch-tuesday-fixes-1-411-flaws-3-zero-days/" rel="noopener noreferrer"&gt;BleepingComputer: Microsoft October 2026 Patch Tuesday fixes 1,411 flaws&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Black_October_(information_security)" rel="noopener noreferrer"&gt;Wikipedia: Black October (information security)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>php</category>
      <category>news</category>
    </item>
    <item>
      <title>Agents that don't wait for you to ask: the price of privacy and of compute</title>
      <dc:creator>Eduardo Teixeira</dc:creator>
      <pubDate>Sat, 07 Nov 2026 15:57:32 +0000</pubDate>
      <link>https://dev.to/dunirvana/agents-that-dont-wait-for-you-to-ask-the-price-of-privacy-and-of-compute-13hc</link>
      <guid>https://dev.to/dunirvana/agents-that-dont-wait-for-you-to-ask-the-price-of-privacy-and-of-compute-13hc</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published in Portuguese on my blog: &lt;a href="https://programero.blogspot.com/2026/11/agentes-sempre-ligados-privacidade-e-custo.html" rel="noopener noreferrer"&gt;Agentes que não esperam você pedir: o preço da privacidade e da computação&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For years, an AI assistant was something that sat waiting for you to type. You ask, it answers, done. The shift happening now is different: agents that stay on all the time, look at your inbox, learn your goals and go off doing things without anyone asking. In theory that's great. In practice, it opens a conversation that those of us working in tech need to have before granting access to everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;At DevDay on September 29, OpenAI introduced "Dots", agents it describes as always on. Each one has its own cloud computer, with a browser, and connects to thousands of apps through plugins. You can talk to it through ChatGPT or through Slack and Teams, and it runs several projects in parallel. The first Dot is included in the Pro and Business Premium plans, and on the Pro plan the feature hasn't yet reached the European Economic Area, Switzerland and the UK.&lt;/p&gt;

&lt;p&gt;There's a layer of control: rules for when to act alone and when to ask, custom rules to allow, block or require approval for specific actions, and an automatic review before anything that touches accounts or shares information. Changing a password, for example, is still the user's job. OpenAI itself warns that the agent can make mistakes and that all important work needs human review.&lt;/p&gt;

&lt;p&gt;This week, Fortune tied together two threads that usually run separately in this discussion: privacy and the cost of compute.&lt;/p&gt;

&lt;h2&gt;
  
  
  The price of privacy
&lt;/h2&gt;

&lt;p&gt;According to the report, Meredith Whittaker, president of Signal, has been warning that personal agents need deep access to your data to work, and that creates security and privacy risk. The point that struck me most is about consent: whoever sends an email or message to a person using one of these agents never agreed to have an AI read it. The access you grant carries along the correspondence of everyone you talk to.&lt;/p&gt;

&lt;p&gt;OpenAI's own head of developer experience, Romain Huet, suggests gradual trust: start with the calendar and only later open up Slack and Gmail. He says he lets his Dot categorize emails and draft replies, but never send messages on his behalf. It's sensible advice, and it applies to any agent, from any company.&lt;/p&gt;

&lt;h2&gt;
  
  
  The price of compute
&lt;/h2&gt;

&lt;p&gt;An always-on agent costs more than a chatbot. An OpenAI executive admitted that Dots are "compute heavy", and the company already routes part of the work to a smaller model, Terra, which according to OpenAI delivers even better results on some tasks, like computer use and writing, at a tenth of the price. On the side of those paying the bill, Fortune cites Menlo Ventures data: companies spent US$ 177 billion on AI in the 12 months through September, more than five times the previous period, and spent well above what they had budgeted. It also reports that Apple lowered the daily AI spending cap for some engineers from US$ 300 to US$ 200.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters if you work in tech
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Permissions become an architecture decision.&lt;/strong&gt; Whoever integrates agents with internal systems will need to think about least privilege, separate credentials, an audit trail and a way to pause everything. It's the same reasoning as for any service account, except this account now takes initiative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost becomes part of the design.&lt;/strong&gt; If the agent runs all day, the token budget stops being an end-of-project detail. Routing between large and small models will likely become common practice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy is about third parties too.&lt;/strong&gt; In a country with a data protection law like Brazil's LGPD, delegating email and chat reading to an agent means looking at what that implies for clients and colleagues, not just for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My take
&lt;/h2&gt;

&lt;p&gt;I find the idea promising and the moment still immature. The technical side is evolving fast, but usage habits are still in "allow everything and see what happens" mode. I'd treat an agent like this the way I'd treat a very fast intern: start with read access to a few things, approve what it does before it leaves the building, and only expand trust with evidence. And I'd pay attention to what the vendor doesn't answer clearly, especially about what happens to the data of people who aren't your users.&lt;/p&gt;

&lt;p&gt;It's also worth being wary of collective enthusiasm. When the cost is still being subsidized and the access rules change every quarter, any critical process relying on an agent needs a plan B. Use it, yes. Blind dependence, no.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fortune.com/2026/11/05/openais-dots-are-coming-up-against-the-price-of-privacy-and-the-price-of-compute" rel="noopener noreferrer"&gt;Fortune - OpenAI's Dots are coming up against the price of privacy, and the price of compute (Nov 5, 2026)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcrunch.com/2026/09/29/openai-launches-dots-its-bubbly-agentic-avatar/" rel="noopener noreferrer"&gt;TechCrunch - OpenAI launches dots, its bubbly agentic avatar (Sep 29, 2026)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thenextweb.com/news/openai-dots-always-on-ai-agents-cloud-computers-devday" rel="noopener noreferrer"&gt;The Next Web - OpenAI launches Dots, always-on AI agents with their own cloud computers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>privacy</category>
      <category>security</category>
      <category>agents</category>
    </item>
    <item>
      <title>Rate limiting in Minimal APIs with .NET's built-in middleware</title>
      <dc:creator>Eduardo Teixeira</dc:creator>
      <pubDate>Sat, 07 Nov 2026 15:56:44 +0000</pubDate>
      <link>https://dev.to/dunirvana/rate-limiting-in-minimal-apis-with-nets-built-in-middleware-25mo</link>
      <guid>https://dev.to/dunirvana/rate-limiting-in-minimal-apis-with-nets-built-in-middleware-25mo</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published in Portuguese on my blog: &lt;a href="https://programero.blogspot.com/2026/11/rate-limiting-minimal-apis.html" rel="noopener noreferrer"&gt;Rate limiting em Minimal APIs com o middleware nativo do .NET&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every API exposed to the internet will, sooner or later, get a client that decides to hit the same endpoint a thousand times per second. It might be a bug in a retry loop, a poorly written script or someone trying their luck. If you have no limit at all, the database, the CPU and your other users pay the bill.&lt;/p&gt;

&lt;p&gt;The good news is that since .NET 7, rate limiting ships with the framework. No extra package, no third-party library. In this post I build a small example with Minimal APIs, per-IP limits, a 429 response with &lt;code&gt;Retry-After&lt;/code&gt; and integration tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea
&lt;/h2&gt;

&lt;p&gt;The middleware works with two concepts: the &lt;strong&gt;limiter&lt;/strong&gt; (the algorithm: fixed window, sliding window, token bucket or concurrency) and the &lt;strong&gt;partition&lt;/strong&gt; (who is being limited). Without a partition, the limit is global, and one abusive client takes the service down for everyone. Partitioning by IP gives each client its own bucket.&lt;/p&gt;

&lt;p&gt;You register a named policy and then apply it to the endpoints that need it. Endpoints like health checks usually stay out, otherwise the orchestrator may decide your application is down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Registering the policy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRateLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RejectionStatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status429TooManyRequests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"por-ip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;RateLimitPartition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFixedWindowLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;partitionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RemoteIpAddress&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"anonimo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FixedWindowRateLimiterOptions&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;PermitLimit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Window&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;windowSeconds&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;QueueLimit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
            &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;QueueLimit = 0&lt;/code&gt; makes excess requests get rejected right away instead of waiting in a queue for the next window. For a public API, that's usually what you want. The limit and window values come from configuration, which helps a lot when testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Telling the client when to come back
&lt;/h2&gt;

&lt;p&gt;Returning 429 without saying when to try again forces the client to guess, and guessing turns into aggressive retries. The &lt;code&gt;OnRejected&lt;/code&gt; callback lets you send back a &lt;code&gt;Retry-After&lt;/code&gt; header with the time left in the window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnRejected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MetadataName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RetryAfter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RetryAfter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalSeconds&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ValueTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Applying it to the endpoints
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseRateLimiter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ola"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hora&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireRateLimiting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"por-ip"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// no limit&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A detail that catches a lot of people: &lt;code&gt;UseRateLimiter()&lt;/code&gt; has to come before mapping the endpoints that use the policy, and the &lt;code&gt;partial class Program&lt;/code&gt; at the end exists only so the test project can see the class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing it for real
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;WebApplicationFactory&lt;/code&gt; you can spin up the application in memory and override the configuration. I lower the limit to 3 requests and keep the window long, so the test doesn't depend on timing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Requisicao_acima_do_limite_retorna_429_com_retry_after&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TooManyRequests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Retry-After"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also a test making sure &lt;code&gt;/health&lt;/code&gt; handles ten calls in a row without getting a 429. It's the kind of regression that slips by until the day the load balancer pulls your application out of rotation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running with Docker
&lt;/h2&gt;

&lt;p&gt;The project has a multi-stage Dockerfile with two targets, &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;tests&lt;/code&gt;, and the compose file exposes both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;span class="c"&gt;# in another terminal, call it more than 5 times within 10 seconds&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 7&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code} "&lt;/span&gt; localhost:8080/&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done

&lt;/span&gt;docker compose run &lt;span class="nt"&gt;--rm&lt;/span&gt; tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like &lt;code&gt;200 200 200 200 200 429 429&lt;/code&gt;. If you look at the headers of the rejected response, &lt;code&gt;Retry-After&lt;/code&gt; will be there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before going to production
&lt;/h2&gt;

&lt;p&gt;This limiter lives in the memory of each instance. With several replicas behind a load balancer, each one counts on its own, so the effective limit is multiplied by the number of instances. If you need a global, exact limit, the way to go is a shared counter, usually in Redis, or delegating it to the gateway.&lt;/p&gt;

&lt;p&gt;Behind a reverse proxy, &lt;code&gt;RemoteIpAddress&lt;/code&gt; will be the proxy's IP, not the client's. Configure &lt;code&gt;ForwardedHeaders&lt;/code&gt; first, otherwise all users fall into the same partition and share the same limit.&lt;/p&gt;

&lt;p&gt;For day-to-day work, the built-in middleware handles most basic protection scenarios well, with no dependencies at all.&lt;/p&gt;

&lt;p&gt;The full code is at &lt;a href="https://github.com/dunirvana/programero-csharp/tree/main/2026-11-rate-limiting-minimal-apis" rel="noopener noreferrer"&gt;programero-csharp/2026-11-rate-limiting-minimal-apis&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>aspnetcore</category>
      <category>api</category>
    </item>
    <item>
      <title>Clojure - Símbolos globais e locais</title>
      <dc:creator>Eduardo Teixeira</dc:creator>
      <pubDate>Fri, 18 Feb 2022 18:20:00 +0000</pubDate>
      <link>https://dev.to/dunirvana/clojure-simbolos-globais-e-locais-482g</link>
      <guid>https://dev.to/dunirvana/clojure-simbolos-globais-e-locais-482g</guid>
      <description>&lt;p&gt;Até agora, sempre que foi necessário manter um valor em memória nós usamos o conceito de "variável", realizando a "definição de um símbolo" com o comando "def". Porém essa abordagem corresponde ao que conhecemos nas linguagens mais tradicionais como "definição de variável global".&lt;/p&gt;

&lt;p&gt;Como é de conhecimento, as definições de "variáveis globais" podem trazer uma série de problemas as aplicações, uma vez que é quase impossível ter conhecimento de todas, com isso podemos acabar gerando problemas com a substituição de valores durante seu uso, podendo causar erros em diversos pontos da aplicação e tornando a aplicação instável e de difícil manutenção.&lt;/p&gt;

&lt;p&gt;Dito isso, veremos como trabalhar com símbolos dentro de um escopo limitado, seguiremos os próximos exemplos dentro de nossas funções.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escopo global
&lt;/h2&gt;

&lt;p&gt;Como vimos até aqui, os símbolos de escopo global podem ser acessados de qualquer parte da aplicação, vamos ao exemplo, considerando uma aplicação hipotética de uma escola, temos duas rotinas distintas que mostram a média dos alunos em duas condições distintas:&lt;/p&gt;

&lt;p&gt;Uma que mostra e média "padrão" acrescida de um ponto extra;&lt;br&gt;
Outra que mostra a média do aluno em uma condição de "recuperação", que acresce a média dois pontos extras;&lt;br&gt;
Enquanto a rotina que mostra a média "padrão" olha para um símbolo global para fazer seu cálculo sem fazer qualquer alteração a rotina que mostra a média dos alunos em condição de "recuperação" também utiliza o mesmo símbolo global, porém ela sempre altera seu valor para "dois".&lt;/p&gt;

&lt;p&gt;O problema que teremos é o seguinte, enquanto a rotina que mostra as médias de alunos em "recuperação" não for executada a rotina de média "padrão", quando executada, apresentará um resultado correto, porém após primeira execução da rotina de "recuperação" a "padrão" começará a mostrar um resultado errado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(def ponto-extra 1)

(defn verifica-situacao-aluno-padrao
  "Retorna a media do aluno somada a seu ponto extra"
  [nota1 nota2]
  (+ (/ (+ nota1 nota2) 2) ponto-extra)
)
(defn verifica-situacao-aluno-recuperacao
  "Retorna a media do aluno somada a seu ponto extra (em caso de recuperação)"
  [nota1 nota2]
  (def ponto-extra 2)
  (+ (/ (+ nota1 nota2) 2) ponto-extra)
)

ponto-extra
(verifica-situacao-aluno-padrao 5 5)
(verifica-situacao-aluno-recuperacao 5 5)
(verifica-situacao-aluno-padrao 5 5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Faqoy2v7g149g7pywu7md.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%2Faqoy2v7g149g7pywu7md.png" alt="Exemplificando um problema com símbolo global" width="721" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sobre a imagem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na linha três definimos nosso símbolo global "ponto-extra";&lt;/li&gt;
&lt;li&gt;Da linha cinco até a linha dezesseis definimos nossas duas funções, "padrão" e "recuperação" respectivamente;&lt;/li&gt;
&lt;li&gt;Na linha dezenove checamos o valor do nosso símbolo global "ponto-extra", que é "1";&lt;/li&gt;
&lt;li&gt;Na linha vinte e um consultamos a situação de um aluno com a rotina "padrão" e vemos que sua média é "6";&lt;/li&gt;
&lt;li&gt;Na linha vinte e três consultamos a situação de um aluno com a rotina de "recuperação" e vemos que sua média é "7";&lt;/li&gt;
&lt;li&gt;Na linha vinte e cinco consultamos a situação de um aluno com a rotina "padrão" novamente e agora vemos um resultado diferente, sua média passou a ser "7", mesmo valor que a rotina de "recuperação";&lt;/li&gt;
&lt;li&gt;Na linha vinte e sete checamos o valor do nosso símbolo global "ponto-extra" novamente, e conforme esperado ele agora é "2";&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conforme já explicado, a função de "recuperação" altera o valor do símbolo global que é usado por outras funções, essa mudança não era esperada em outras partes da aplicação e isso gerou um problema de divergência de valores, e pior, a momentos onde o problema não ocorre (já que ele só ocorre a partir da primeira execução da rotina de "recuperação") e a rotinas que continuam a funcionar (a rotina "recuperação" sempre funciona). Acabamos de gerar um bug em nossa aplicação que não será nada fácil de simular/encontrar/corrigir.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escopo local
&lt;/h2&gt;

&lt;p&gt;Como visto anteriormente, o uso inadequado de um símbolo global gerou um bug em nossa aplicação, para resolver esse problema o desenvolvedor que criou a função de "recuperação" deveria ter usado um símbolo de escopo local na rotina, uma vez que o valor de "ponto-extra" usado ali é uma regra especifica dessa rotina.&lt;/p&gt;

&lt;p&gt;Para trabalharmos com o escopo local utilizaremos a função "let", com ele criamos um escopo local com símbolos e funções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O "let" deve ser usado entre parênteses;&lt;/li&gt;
&lt;li&gt;Ele recebe um vetor de símbolos/valores;&lt;/li&gt;
&lt;li&gt;Ele recebe uma ou mais funções;&lt;/li&gt;
&lt;li&gt;Ele retorna o resultado da execução de sua última função;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(let [idade 40] (+ idade 1))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fafdrv4w30zcz3u5m4xuw.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%2Fafdrv4w30zcz3u5m4xuw.png" alt="Usando o let pela primeira vez" width="432" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na linha um criamos nosso escopo local com o "let", nesse escopo temos o símbolo "idade" com o valor "40" dentro do vetor e temos uma função que soma a valor "1" ao nosso símbolo "idade";&lt;/li&gt;
&lt;li&gt;Na linha dois temos o resultado da função de soma;&lt;/li&gt;
&lt;li&gt;Na linha três tentamos usar o símbolo "idade" e recebemos um erro na sequencia dizendo que não foi possível resolver o símbolo;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bom, agora que já sabemos como resolver o problema de escopo vamos aplicar uma correção em nossa função "recuperação", para que ela deixe de usar o símbolo global, primeiro vamos reiniciar o símbolo global para seu valor correto, em seguida vamos corrigir a função e ne sequencia executar os testes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(def ponto-extra 1)

(defn verifica-situacao-aluno-recuperacao
  "Retorna a media do aluno somada a seu ponto extra (em caso de recuperação)"
  [nota1 nota2]
  (let [ponto-extra-recuperacao 2]
    (+ (/ (+ nota1 nota2) 2) ponto-extra-recuperacao))  
)

(verifica-situacao-aluno-padrao 5 5)
(verifica-situacao-aluno-recuperacao 5 5)
(verifica-situacao-aluno-padrao 5 5)
ponto-extra
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F4i6ciqsv6lfc67tzkfu5.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%2F4i6ciqsv6lfc67tzkfu5.png" alt="Refatorando a função para uso do escopo local" width="708" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na linha 1 redefinimos nosso símbolo global para seu valor correto;&lt;/li&gt;
&lt;li&gt;Da linha três até a oito temos a refatoração de nossa função com o uso do "let";&lt;/li&gt;
&lt;li&gt;Nas linhas dez, doze e catorze repetimos os testes, e agora os seus respectivos resultados estão corretos;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Nesse post entendemos e exemplificamos os problemas causados pelo uso do escopo global, vimos como trabalhar com escopo local com o "let" e refatoramos nossa função problemática para que nossa aplicação voltasse a funcionar da forma esperada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saiba mais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://clojure.org/" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://clojure.org/about/functional_programming" rel="noopener noreferrer"&gt;Functional Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://programero.blogspot.com/2022/02/clojure-simbolos-globais-e-locais.html" rel="noopener noreferrer"&gt;Escrito originalmente aqui&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>braziliandevs</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Clojure - Criando nossa primeira função</title>
      <dc:creator>Eduardo Teixeira</dc:creator>
      <pubDate>Wed, 09 Feb 2022 17:26:29 +0000</pubDate>
      <link>https://dev.to/dunirvana/clojure-criando-nossa-primeira-funcao-1cdj</link>
      <guid>https://dev.to/dunirvana/clojure-criando-nossa-primeira-funcao-1cdj</guid>
      <description>&lt;p&gt;Anteriormente vimos como configurar o ambiente e em seguida escrevemos nossas primeiras linhas de código para começarmos a entender como o Clojure funciona, usamos algumas funções "nativas", declaramos algumas "variáveis" e também brincamos com um vetor.&lt;/p&gt;

&lt;p&gt;Nesse post daremos mais um passo, escreveremos nossa primeira função, passando por algumas de suas características e entendendo um pouco sobre como a criação delas funciona.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definindo nossa primeira função
&lt;/h2&gt;

&lt;p&gt;Para criar nossa primeira função precisamos ter em mente que o que deve ser feito é algo semelhante a definição de uma variável, a diferença fica por conta do uso do comando "defn" (é possível usar o "def", mas veremos isso futuramente), basicamente precisaremos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Escrever todo o conteúdo dentro de parênteses;&lt;/li&gt;
&lt;li&gt;Usar o comando "defn";&lt;/li&gt;
&lt;li&gt;Definir uma lista de parâmetros, se não existirem parâmetros (nosso caso agora) essa lista deve estar vazia;&lt;/li&gt;
&lt;li&gt;Definir o corpo da função;&lt;/li&gt;
&lt;li&gt;Opcionalmente podemos colocar um comentário para deixar mais claro o que a função faz;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Definindo nossa função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(defn minha-primeira-funcao
  "Exemplo de uma função"
  []
  (println "Minha primeira função!")
)

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

&lt;/div&gt;



&lt;p&gt;Executando nossa função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(minha-primeira-funcao)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Ftwyra48854iybxuxa8ci.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%2Ftwyra48854iybxuxa8ci.png" alt="Criando nossa primeira função!" width="343" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima temos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na linha três temos o inicio da definição de nossa função com o uso de "defn" seguido do nome que escolhemos;&lt;/li&gt;
&lt;li&gt;Na linha quatro, entre aspas duplas, temos o comentário que explica o que a função faz;&lt;/li&gt;
&lt;li&gt;Na linha cinco temos o vetor de parâmetros vazio;&lt;/li&gt;
&lt;li&gt;Na linha seis temos o corpo de nossa função, que realiza a impressão no console de uma frase;&lt;/li&gt;
&lt;li&gt;Na linha sete temos o fechamento de nossa função;&lt;/li&gt;
&lt;li&gt;Na linha nove executamos a nossa função;&lt;/li&gt;
&lt;li&gt;Na linha dez temos o resultado da execução e na onze o retorno;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apenas um detalhe, a função toda foi escrita no bloco de notas, e depois copiada para o console para a execução.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando uma função que recebe parâmetros e devolve um valor
&lt;/h2&gt;

&lt;p&gt;De acordo com nosso exemplo anterior, para criarmos uma função que receba parâmetros basta declara-los no vetor que tem essa responsabilidade, agora para retornar um valor basta construirmos uma instrução que retorne um valor.&lt;/p&gt;

&lt;p&gt;Para nosso segundo exemplo criaremos uma função que calculará e retornará a média de um aluno com base em duas notas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(defn calcula-media
  "Calculando a media de duas notas"
  [nota1, nota2]
  (/ (+ nota1 nota2) 2)
)

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

&lt;/div&gt;



&lt;p&gt;Executando nossa segunda função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(calcula-media 7M 8M)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fmoghpasrl4jqhd68whv6.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%2Fmoghpasrl4jqhd68whv6.png" alt="Função que calcula a média de duas notas" width="348" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima temos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Da linha três a linha sete temos a definição de nossa função, destaque para a linha cinco onde temos a definição de dois parâmetros (nossas duas notas) e para a linha seis, onde de fato realizamos o cálculo e por consequência o retorno da média, analisando de "dentro" para "fora" temos a soma das notas e depois a divisão por dois;&lt;/li&gt;
&lt;li&gt;Na linha nove temos a execução da função de média, onde informamos as duas notas, a "letra M" colocada junto do valor das notas é apenas para termos um resultado mais amigável, a frente entenderemos melhor a questão de tipos de dados;&lt;/li&gt;
&lt;li&gt;E na linha dez temos o resultado apresentado, a média calculada;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Nesse post escrevemos nossas duas primeiras funções e entendemos como passar parâmetros e devolver um resultado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saiba mais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://clojure.org/" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://clojure.org/guides/learn/functions" rel="noopener noreferrer"&gt;Learn Clojure - Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://programero.blogspot.com/2022/02/clojure-criando-nossa-primeira-funcao.html" rel="noopener noreferrer"&gt;Escrito originalmente aqui&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>beginners</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Clojure - Funções, vetores e def</title>
      <dc:creator>Eduardo Teixeira</dc:creator>
      <pubDate>Mon, 07 Feb 2022 12:28:47 +0000</pubDate>
      <link>https://dev.to/dunirvana/clojure-funcoes-vetores-e-def-4133</link>
      <guid>https://dev.to/dunirvana/clojure-funcoes-vetores-e-def-4133</guid>
      <description>&lt;p&gt;Nessa postagem escreveremos nossas primeiras linhas de código com o Clojure, aqui tentaremos trazer alguns conceitos para mais perto de quem já programa com os paradigmas mais tradicionais (orientação a objetos por exemplo), de modo que fique mais simples entender as intenções e começarmos a correlacionar alguns pontos, mesmo que alguns deles não sejam necessariamente a mesma coisa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Funções
&lt;/h2&gt;

&lt;p&gt;Como já é de conhecimento, funções são pequenas partes de um programa que executam um trabalho e devolvem um resultado, e para que esse trabalho seja realizado muitas vezes é necessário informar argumentos ou informações para que algo seja feito.&lt;/p&gt;

&lt;p&gt;Em Clojure toda invocação de uma função ocorre dentro de parênteses, logo podemos interpretar o conteúdo que esta dentro dos parênteses da seguinte forma:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O primeiro valor é a função a ser executada;&lt;/li&gt;
&lt;li&gt;O segundo valor é o primeiro argumento que a função receberá;&lt;/li&gt;
&lt;li&gt;Vamos agora ao nosso primeiro exemplo, iremos chamar uma função que escreve no console, passando como "argumento" o famoso "Olá Mundo!":
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(println "Olá Mundo!")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fzoybd0a23qqi37z2r7ob.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%2Fzoybd0a23qqi37z2r7ob.png" alt="Nosso primeiro comando!" width="360" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos falar sobre a imagem agora, linha por linha:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na primeira linha estamos iniciando o Clojure com o comando "clj";&lt;/li&gt;
&lt;li&gt;Na segunda linha nos é apresentada a versão atual (1.10.3);&lt;/li&gt;
&lt;li&gt;Na terceira linha começamos a escrever nosso primeiro código, chamando a função "println";&lt;/li&gt;
&lt;li&gt;Na quarta linha temos o resultado da execução interna da função "println", que é a escrita no console da frase que informamos como "argumento";&lt;/li&gt;
&lt;li&gt;Na quinta linha temos o retorno da função "println", como ela não retorna nada recebemos nulo (nil);&lt;/li&gt;
&lt;li&gt;Na sexta e última linha temos o controle a disposição novamente para informar os próximos comandos;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ainda sobre funções vale destacar que os operadores matemáticos também são considerados como funções, logo se quisermos somar dois números, por exemplo, precisaríamos iniciar a expressão com o operador de soma, seguido dos "argumentos" (números) que desejamos somar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(+ 1 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Iniciar a a expressão com um número, utilizando um padrão de operação comum nas linguagens  de programação mais tradicionais resultaria em erro, uma vez que o Clojure tentaria interpretar um número como uma função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(1 + 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fczx95bmspq1oeyau1pfq.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%2Fczx95bmspq1oeyau1pfq.png" alt="Somando dois números" width="550" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima vemos os dois exemplos, o primeiro com o resultado correto, onde a soma é o primeiro parâmetro e o segundo com o resultado incorreto, onde o Clojure nos diz que o número informado não é uma função.&lt;/p&gt;

&lt;h2&gt;
  
  
  def
&lt;/h2&gt;

&lt;p&gt;Quando estamos programando é trivial mantermos determinados valores (independente do tipo) armazenados em memória, para podermos acessá-los durante a execução de uma aplicação ou função e comumente realizamos isso por meio de "variáveis", sendo justamente esse o conceito que utilizaremos agora para tentar entender o "def".&lt;/p&gt;

&lt;p&gt;Com o "def" criamos (ou definimos) símbolos que nos permitem salvar e recuperar determinados valores, funcionando de forma semelhante a uma variável, sua sintaxe é simples, e funciona como uma função, onde temos a função propriamente dita, o símbolo a ser criado/atualizado e o valor que pretendemos associar ao símbolo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(def total-de-alunos 25)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para poder ver o valor armazenado em nosso símbolo podemos usar o "println" ou podemos ver seu conteúdo simplesmente digitando o nome do símbolo (fora de parentes é claro):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(println total-de-alunos)

total-de-alunos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fkuvox0l2zeuj1gmj3v4t.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%2Fkuvox0l2zeuj1gmj3v4t.png" alt="Definindo um símbolo e vendo seu conteúdo" width="391" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima vemos o seguinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na linha três a definição do símbolo "total-de-alunos" com o valor "25";&lt;/li&gt;
&lt;li&gt;Na linha quatro o retorno que nos indica o espaço onde nosso símbolo esta gravado (user);&lt;/li&gt;
&lt;li&gt;Na linha cinco executamos a função "println" para ver o conteúdo;&lt;/li&gt;
&lt;li&gt;Na linha oito verificamos o valor do símbolo diretamente, sem o uso de uma função;&lt;/li&gt;
&lt;li&gt;Nas linhas seis e nove podemos ver o valor armazenado no símbolo;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para alterar o valor de um símbolo basta utilizarmos o "def" novamente, informando o identificador e o novo valor, esse novo valor pode ser um número fixo (como vimos anteriormente) ou pode ser a execução de uma outra função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(def total-de-alunos 30)

(def total-de-alunos (+ total-de-alunos 5))

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

&lt;/div&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%2Fi7jjna7mxcr2770r0c0d.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%2Fi7jjna7mxcr2770r0c0d.png" alt="Alterando o valor do símbolo" width="461" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos observar na imagem acima:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na linha um definimos um novo valor para o símbolo;&lt;/li&gt;
&lt;li&gt;Na linha três pedimos para ver o novo valor e na linha quatro o vemos (30);&lt;/li&gt;
&lt;li&gt;Na linha cinco alteramos o valor novamente, fazendo com que o novo valor seja o valor já existente "30" somado a "5";&lt;/li&gt;
&lt;li&gt;Na linha sete pedimos para ver o novo valor e na linha oito o vemos (35);&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vetores
&lt;/h2&gt;

&lt;p&gt;Quando começamos a aprender uma nova linguagem de programação umas das primeiras estruturas que aprendemos para armazenar uma série de elementos é o vetor, em Clojure não é diferente, a exemplo do que vimos anteriormente, iremos usar o "def" para definir um símbolo ficando por conta do valor atribuído a definição desse vetor, em nosso caso iremos atribuir uma série de nomes entre colchetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(def alunos ["Maria", "Flávia", "Teresa"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que no comando acima utilizamos "virgulas" para separar os elementos, mas o que conta mesmo para essa separação são os espaços, a virgula esta ali apenas como uma boa prática que nos permite identificar melhor os itens (inclusive as virgulas são consideradas como espaços no Clojure).&lt;/p&gt;

&lt;p&gt;Para ver os itens de nosso vetor podemos usar tanto as formas já vistas até aqui, com o "println" ou digitando o nome do símbolo diretamente, o que resulta na apresentação de todos os valores ou podemos acessá-los por meio de suas posições, nesse último caso o vetor acaba funcionando como uma função que recebe como parâmetro a posição desejada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(println alunos)

alunos

(alunos 2)

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

&lt;/div&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%2F22c8jzvj67uhnwlwoukw.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%2F22c8jzvj67uhnwlwoukw.png" alt="Criando o vetor e vendo seu conteúdo" width="468" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando trabalhamos com vetor temos a disposição a função "count" para contar o total de elementos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(count alunos)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora se nossa intenção for adicionar um novo item ao vetor devemos usar a função "conj", aqui é muito importante entendermos que essa função não altera o vetor original, o que ela faz é retornar um novo vetor que possui os valores anteriores e também o novo, isso devido a imutabilidade do Clojure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(conj alunos "Eduardo")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas qual a vantagem da imutabilidade então? Bom ela nos garante que nossa informação (no caso os valores de nosso vetor) não serão alterados sem o nosso conhecimento ao utilizarmos outras funções, desse modo temos uma confiabilidade maior sobre a informação uma vez que ela só será alterada se realmente desejarmos, ou seja, não corremos o risco de termos os dados alterados por uma função que se quer conhecemos a implementação.&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%2Fzzh6xf6ra2aenquubi6c.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%2Fzzh6xf6ra2aenquubi6c.png" alt="Adicionando valor ao vetor sem alterá-lo" width="462" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima temos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Na linha sete usamos a função "conj" para adicionar um elemento ao vetor;&lt;/li&gt;
&lt;li&gt;Na linha oito a função "conj" nos retorna o novo vetor contendo a alteração que realizamos;&lt;/li&gt;
&lt;li&gt;Na linha nove e dez podemos perceber que o vetor original "alunos" não foi alterado;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Certo, como já é possível imaginar, se nossa intenção for alterar o vetor original precisaremos então redefinir o valor do nosso símbolo "vetor", sendo que seu novo valor será o resultado da execução da função "conj":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(def alunos (conj alunos "Eduardo"))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fy1a4oayui1byvbaf11vh.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%2Fy1a4oayui1byvbaf11vh.png" alt="Novo valor no vetor original" width="397" height="97"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podemos ver na imagem acima agora o vetor original "alunos" possui o novo valor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Nessa postagem sentimos o gostinho inicial do Clojure, escrevemos nosso primeiro "Olá Mundo!", definimos nossa primeira "variável" e criamos nosso primeiro vetor. Também nos deparamos com a imutabilidade, entendendo como ela funciona e uma de suas principais vantagens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saiba mais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://clojure.org/" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://clojure.org/guides/learn/syntax" rel="noopener noreferrer"&gt;Learn Clojure - Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://programero.blogspot.com/2022/02/clojure-funcoes-vetores-e-def.html" rel="noopener noreferrer"&gt;Escrito originalmente aqui&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>beginners</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Clojure - Preparando o ambiente</title>
      <dc:creator>Eduardo Teixeira</dc:creator>
      <pubDate>Thu, 03 Feb 2022 18:56:19 +0000</pubDate>
      <link>https://dev.to/dunirvana/clojure-preparando-o-ambiente-8m</link>
      <guid>https://dev.to/dunirvana/clojure-preparando-o-ambiente-8m</guid>
      <description>&lt;p&gt;Antes de mais nada precisamos preparar nosso ambiente para podermos começar a brincar, no link oficial temos os processos de instalação de acordo com os SOs suportados, nessa postagem iremos falar sobre as instalações no Linux e no Windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Windows
&lt;/h2&gt;

&lt;p&gt;Para a instalação no Windows podemos usar o instalador ou fazer o processo via linha de comando com o PowerShell, esse último seguindo as seguintes instruções (conforme indicado aqui):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se certificar que o PowerShell esta na versão 5 ou posterior, para tal basta abrir o mesmo (pressione "Windows + X", escolha "Executar" e digite o comando "Powershell"), e em seguida digitar o comando "get-host":&lt;/li&gt;
&lt;/ul&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%2Fx5tanm37arc9pa8o6ng3.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%2Fx5tanm37arc9pa8o6ng3.png" alt="Versão do PowerShell" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Também devem estar instalados o ".NET Core SDK 2.1+ or .NET Framework 4.5+ (ou mais recente)". Além disso precisaremos do Java 8+ e a variável de ambiente JAVA_HOME configurada;&lt;/li&gt;
&lt;li&gt;Se tudo estiver certo basta executar o comando para o download "iwr -useb download.clojure.org/install/win-install-1.10.3.1058.ps1 | iex":&lt;/li&gt;
&lt;/ul&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%2Fjd9630jfgr5nkcrveauo.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%2Fjd9630jfgr5nkcrveauo.png" alt="Baixando o Clojure" width="799" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Como podemos ver acima, após o download nos é apresentada uma lista de possíveis locais para a instalação, no nosso caso escolheremos a opção "2":&lt;/li&gt;
&lt;/ul&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%2Fgaox959fogq6yz5vohk4.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%2Fgaox959fogq6yz5vohk4.png" alt="Instalando o Clojure" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se tudo correu bem até aqui temos nossa configuração inicial pronta;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Linux
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Em nosso caso estamos usando a distribuição Ubuntu 18.4;&lt;/li&gt;
&lt;li&gt;Precisamos garantir que as seguintes dependências estão instaladas: bash, curl, rlwrap e o Java (em nosso caso precisamos instalar apenas o Java,  e para tal utilizamos esse artigo);&lt;/li&gt;
&lt;li&gt;Se estiver tudo OK basta baixar um script pronto (com o curl), depois executar ele:&lt;/li&gt;
&lt;/ul&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%2Fh1ir1dbt73173xy1opfd.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%2Fh1ir1dbt73173xy1opfd.png" alt="Baixando e instalando o Clojure no Linux" width="751" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Concluímos a instalação base do Clojure tanto no Windows como no Linux, nas próximas postagens começaremos nossa caminhada!&lt;/p&gt;

&lt;h2&gt;
  
  
  Saiba mais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://clojure.org/" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://clojure.org/guides/getting_started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/como-instalar-o-java-com-apt-no-ubuntu-18-04-pt" rel="noopener noreferrer"&gt;Instalando o Java no Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://programero.blogspot.com/2022/02/clojure-preparando-o-ambiente.html" rel="noopener noreferrer"&gt;Escrito originalmente aqui&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>functional</category>
      <category>beginners</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
