<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Thiago Ferreira on Medium]]></title>
        <description><![CDATA[Stories by Thiago Ferreira on Medium]]></description>
        <link>https://medium.com/@tferreiraw?source=rss-18a8fd20a75c------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*9-K8WzITVrNEu7a4iYb5Yg.jpeg</url>
            <title>Stories by Thiago Ferreira on Medium</title>
            <link>https://medium.com/@tferreiraw?source=rss-18a8fd20a75c------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 06:24:10 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@tferreiraw/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Does software design even matter now with LLMs?]]></title>
            <link>https://medium.com/@tferreiraw/does-software-design-even-matter-now-with-llms-4107c4b6c38c?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/4107c4b6c38c</guid>
            <category><![CDATA[code-quality]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[ai-coding-agent]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Mon, 09 Mar 2026 13:33:39 GMT</pubDate>
            <atom:updated>2026-03-09T13:33:39.980Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CjmjzFZ48SJ2S1KUU7wgdA.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/pt-br/@th_mdz">https://unsplash.com/pt-br/@th_mdz</a> (that&#39;s me!)</figcaption></figure><p>WOW! It’s been so long since my last post here. So much has happened in the tech industry, and I’m back to share some insights into what I’ve been learning.</p><p>I explored in a previous post in 2023 how the LLMs are a great tool to help <a href="https://medium.com/@tferreiraw/terraform-chatgpt-how-to-beat-the-learning-curve-f72ae861708b"><strong>overcome the learning curve</strong></a>. After that, coding agents started becoming more powerful and independent.</p><p>Back to the core question of this article:</p><blockquote><strong>Does it even matter if we try to do good Software design?</strong><br><br><strong>Does it matter if we spend time doing code reviews so new code is readable, coherent, manageable for the future, if LLMs can handle it as is? </strong><br> <br><strong>Who cares / Who should care?</strong></blockquote><p>I’m not big on click-baits, so I’m gonna give you the answer right away and then I’ll explain:</p><blockquote>Yes. Software design still matters and there’s an economic argument of why you should care.</blockquote><p>Let’s start!</p><h4>First things first, what am I considering Good Software design?</h4><p>I’m relying mostly on Kent Beck’s definition of software quality. As he rejects abstract definitions, he believes quality has an economic and practical definition.</p><blockquote>Quality software is software that is easy to change.</blockquote><p>That simple. Quality is not about elegance, technical perfection, or absence of bugs. It’s about the <strong>cost of future change</strong>.</p><h4>The economic argument</h4><p>Beck uses the metaphor of financial options:<br>- <strong>Well-structured code</strong> -&gt; you have the option to change cheaply in the future<br>- <strong>Bad code</strong> -&gt; every change is expensive, or impossible<br>- <strong>Tidying code is like buying an option -&gt;</strong> it has a cost now, but reduces risk and future cost</p><p>Were you ever in a position that an apparently simple change became a nightmare? You only needed a simple new field on an API or change a color of a button, and suddenly, you cannot do it simply without disrupting the whole structure.</p><h4>Practical Consequence</h4><p>Code that works but is hard to change has less value than code that works and is easy to change. Even if they look identical from the outside.</p><p>This is the main thing that most people using LLMs to code are not realizing. It might seem cheaper to “vibe code” at the beginning, but the cost of future maintenance is going to skyrocket.</p><h4>Code so humans can understand it. Then LLM will thrive on it.</h4><p>I’ve come across this multiple times now. If you have code that’s very hard to understand, unpredictable, highly coupled, low cohesion… Then LLMs will also struggle on that and make LOTs of mistakes. Be careful in these scenarios.</p><p>On the other hand, If you have code that humans can understand easily, low coupling, high cohesion… all the good stuff from good software design: Congratulations. You now have code that’s cheaper to maintain, easier for humans to understand and the best part: LLMs will THRIVE on it!</p><p>That means we can delegate more things to the AI, with fewer risks that it is going to go the wrong route. In the “bad code” from our example, AI just makes lots of mistakes and gets off-track very easily.</p><h4>Lastly… Beautiful code != functional.</h4><p>When trying to be better at software design, some people try to make it more elegant, beautiful. That’s not what I mean here.</p><p>This is even a problem for me because the focus on the aesthetics can make it harder to spot the problems.</p><p>Instead, focus on:<br>- Structure and relationships of components: if A and B are coupled, every time you change A you also have to change B. Code so you diminish the dependency between components. This is the coupling principle.<br>- Cohesion: Keep things that are related to each other close in the code. It’s awful having to open 5 files to understand what a single process does.</p><h4>What now?</h4><p>If you’re interested in this topic and want to continue reading, my best recommendation is that you first read this book: <strong>Tidy First?: A Personal Exercise in Empirical Software Design</strong></p><p>It’s by Kent Beck, the creator of the TDD methodology over 20 years ago. In this book he says that he took his whole career to be able to summarize the correlation between software design and cost… so you can tell that this is a take on the topic that’s worth reading, isn’t it?</p><h4>Conclusion</h4><p>This is a short insight, there would be so much more than I can put on a medium post. But feel free to reach out or comment below, I’d love to continue the conversation!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4107c4b6c38c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[3 guaranteed ways to make your life miserable as a software engineer]]></title>
            <link>https://medium.com/@tferreiraw/3-guaranteed-ways-to-make-your-life-miserable-as-a-software-engineer-fcfd82918e8f?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/fcfd82918e8f</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[the-clean-coder]]></category>
            <category><![CDATA[agile]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Mon, 18 Dec 2023 13:43:09 GMT</pubDate>
            <atom:updated>2023-12-18T13:43:09.604Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/459/0*0CJqP_NceWufUucN.jpeg" /><figcaption>A meme with an old man in the background and the text “Sofware development is not stressful, says Robert, 22 years old”</figcaption></figure><p>I love this meme. It illustrates how easy it is for people in software engineering roles to be highly stressed — Yikes!</p><p>I often talk to friends working in different, varied types of companies, and if they’re feeling stressed, I can usually pinpoint a few causes for that to be happening to them.</p><p>Some causes may be at an organizational level, but a many things can be solved at the individual level. And as soon as you have a critical mass of individuals doing the right things, organizational culture shifts for the better.</p><p>Let’s then cover a few reasons why you might be over-stressed at work, not to mention a possible downturn in productivity.</p><h3>ℹ️ Hoard information for yourself</h3><p>This is infallible. If you want to be miserable, treat information as currency and hold it as if your life depended on it. Sure, it would probably secure your job, as you’d be the only person knowing about a certain subject, but make no mistake: you’ll pay the price for it.</p><p>If you hoard information and overlook writing documentation, sharing knowledge, and presentations, you’re gonna be <strong>the only point of contact</strong> for that information and you’ll spend most of your days just sharing bits and pieces of information.</p><p>Good luck trying to schedule some time off, as even if you can get so, you’ll leave your team in a precarious position, and they may need to reach out while you are on time off.</p><p>Yikes! That does not sound fun.</p><p>Instead, sharing information will ensure you’ll have time for your meaningful projects. Check out the chapter <a href="https://sre.google/sre-book/eliminating-toil/">Eliminating Toil</a> in the SRE book to understand how you can eliminate tasks with documentation and automation.</p><h3>👍 Always say yes</h3><p>Another great way of becoming miserable is always saying yes to projects, demands, or asks, <strong>even when you are sure it can’t be done</strong> in the desirable time.</p><p>Many software engineers will accept technical challenges, knowing the effort <strong>needs more time than what is available</strong>. They may do this because they feel <strong>insecure</strong> about saying <strong>no</strong> to their managers or product managers, which is a valid concern.</p><p>But isn’t avoiding saying “no” and having <strong>a difficult conversation now, </strong>just <strong>pushing the issue to the future</strong>? If you know it can’t be done in time, it’s best to be honest, responsible, and do the right thing, even if it includes hard conversations in between.</p><p>I love the book <strong>The Clean Coder, by Bob Martin. </strong>The author stresses the need to be responsible and say no when it’s appropriate. Avoid overcommitting and be realistic about what you can accomplish within a time frame.</p><p>This is not to say “always say no”. If you have an unrealistic timeframe to work on, be open with your manager/product manager, <strong>negotiate</strong> with features you can leave out, and/or even <strong>ask for more time</strong>. Everyone will be happy in the end.</p><h3>📈 Lose track of what matters</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/0*I1EVGcLBJbQINFFm.png" /><figcaption>an image showing that if you spend your energy in many directions, you make little progress in each.In contrast with focusing on one thing, and making a lot of progress.</figcaption></figure><p>While the other 2 ways of becoming miserable are more “instant”, I’ll also offer you a way to be miserable in the long run.</p><p>The idea is simple: spend your time on anything you want, <strong>without evaluating how that things plays out in the long run</strong>. This will ensure that you <strong>won’t be focused</strong>, and will spread your energy across many things, without making any meaningful progress in any of them (see image above).</p><p>Well, if you don’t want to be miserable in this aspect, here are my recommendations:</p><ul><li><strong>Always keep an eye on the big picture</strong>. How do projects correlate with the long-term goals?</li><li><strong>Constantly evaluate</strong> if you are spending your efforts on the right things. You may be spending all of your energy solving an issue that no one cares about and may not move the needle at all.</li><li><strong>Don’t treat time as an infinite resource</strong>. It’s easy to go down the rabbit hole in certain projects, but having a good sense of time vs. effortvs. benefits is key to getting this right.</li></ul><p>The book <strong>Essentialism: The Disciplined Pursuit of Less, </strong>by Greg McKeown is a great recommendation on this topic.</p><h3>Conclusion/Disclaimer</h3><p>If you made it this far, you already get the idea. But to be crystal clear:</p><p><strong>PLEASE DO THE OPPOSITE of the topics above.</strong></p><p>Don’t <strong>Hoard information -&gt; </strong>Share it instead.</p><p>Don’t <strong>Always say yes</strong> -&gt; Understand when to say no and when to make compromises</p><p>Don’t <strong>Lose track of what matters -&gt; </strong>Keep a close eye on the picture and pivot as needed to meet your goals.</p><p>This was a fun way to share a few of my thoughts on the subject, along with sharing some <strong>book recommendations</strong> in the process:</p><ul><li>📕 <strong>Site Reliability Engineering</strong></li><li>📕 <strong>The clean coder</strong></li><li>📕<strong>Essentialism: The Disciplined Pursuit of Less</strong></li></ul><p>I hope this was helpful for you, and leave a comment to keep the discussion going 🙌</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fcfd82918e8f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Terraform + ChatGPT: How to beat the learning curve]]></title>
            <link>https://medium.com/@tferreiraw/terraform-chatgpt-how-to-beat-the-learning-curve-f72ae861708b?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/f72ae861708b</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[terraform]]></category>
            <category><![CDATA[chatgpt]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Sun, 01 Oct 2023 20:42:01 GMT</pubDate>
            <atom:updated>2023-10-01T20:42:01.081Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*9ExLGrHoAmVCAeiZ" /><figcaption>Foto de <a href="https://unsplash.com/pt-br/@shanerounce?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Shane Rounce</a> na <a href="https://unsplash.com/pt-br/fotografias/PHKgQSGzwpw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>If you haven’t been in a hole for the past year, you already know that ChatGPT makes a great copilot when working.</p><p>We all have seen thousands of posts on how to get the best out of it, and since I don’t want to miss the party, today I’m adding my own tip to the pile 🌻</p><p>Today we are discussing how I’m beating the learning curve in Terraform using ChatGPT as my copilot 🙌</p><h3>Context — What is Terraform?</h3><p><a href="https://www.terraform.io/">Terraform</a> is an infrastructure-as-code tool to help you define and provision infrastructure resources in the cloud.</p><p>Think about it this way: on any cloud provider, you’ll need to set up a few virtual machine instances, databases, platform-as-a-service apps, etc.</p><p>You’ll also need to connect those resources, like, the application needs to access the database. If you were doing everything manually, you’d create first the database, then the application, then manually include the secrets in the app.</p><p>With Terraform, you can automate the work of creating the resources, configuring some of the secret management, and getting everything up to speed. Amazing, isn’t it?</p><h3>What about that learning curve?</h3><p>I’m not new to Terraform, but the way it works always seemed to get the best of me 😂 I struggled a lot with the syntax, and how to put together more complicated use cases.</p><p>I always find the docs to be a great reference, but miss some of the recipes used in common projects — like separating environments, connecting different resources (like the app and the DB)</p><p>It had been a while since I touched Terraform, and recently I was trying it out again. This time, I used ChatGPT to understand some of those concepts. The result? Stay tuned 👇</p><h3>ChatGPT as a copilot to learn terraform</h3><p>Here are some of my questions:</p><h4>How do I set up that cloud provider token again?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/452/1*8hqfOtEH5d0Ddk1S2BHcYw.png" /></figure><p>Among many options, this is what I needed:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/718/1*-C5vHuFfIgaDuYab_UTZIw.png" /></figure><h4>The concept of `<strong>output</strong>`, how does it work?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/528/1*OU9FBXtZAXm8hhjW7m8CTg.png" /></figure><p>This was really helpful, I wasn’t yet aware we could connect modules this way:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/840/1*UN11nCFk9ZGD2EIOFTC6-g.png" /></figure><h4>How do I interpolate the terraform workspace name into a resource?</h4><p>It is that simple:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/822/1*wjEXk0ncsMXkdU-rY-wmBw.png" /></figure><h4>How do I access outputs from one module, in another?</h4><p>My first question went like this:</p><blockquote>How do I access outputs from other modules?</blockquote><p>The answer was good, but it was not considering that I needed to use the output in a sibling module. I re-asked this way:</p><blockquote>I need to access one module output, in another module output. how’s that possible?</blockquote><p>I won’t copy the full answer, but then it got it right! Here’s what I needed:</p><ul><li>Define output in module A</li><li>Define input variable in module B</li><li>Use the main.tf to pass outputs from A into B</li></ul><p>Then it worked ⚡️</p><h4>Sorting out when something is not possible</h4><p>I was trying to get something done that was not supported yet by the cloud provider. I was trying to get a Digital Ocean’s app platform IP, and here’s what I got:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/859/1*aUtugCwwF52gYtuN86Ql8Q.png" /></figure><p>And that was accurate once again!</p><h3>Final Thoughts</h3><p>I’m sure you already know <strong>but don’t trust ChatGPT blindly.</strong></p><p>ChatGPT will have inconsistencies and mistakes, be sure to double-check the information in the official sources.</p><p>Quoting from a book I was reading on Plato the philosopher, here’s a distinction the author made:</p><blockquote>The world has never had so much available information. Just search for a term, and you’ll get thousands of results. Now it seems that assimilating information is a trivial practice, but make no mistake. All of this available information isn’t always coherent and objective, therefore <strong>accessing information </strong>is not the same <strong>as acquiring knowledge</strong>.<br><a href="https://www.amazon.com.br/Cole%C3%A7%C3%A3o-Saberes-Minutos-Entender-Plat%C3%A3o/dp/8534400083">From this book</a></blockquote><p><strong>That said, do your best to be critical about the information you consume.</strong></p><p>Now, I’m off to go have fun learning concepts that once seemed too scary. Drop a comment if you liked this article 👋</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f72ae861708b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Reverting git commits: 2 simple ways]]></title>
            <link>https://medium.com/@tferreiraw/reverting-git-commits-2-simple-ways-e9374481a10b?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/e9374481a10b</guid>
            <category><![CDATA[deployment]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[git]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Sat, 19 Aug 2023 14:52:11 GMT</pubDate>
            <atom:updated>2023-08-19T14:52:11.637Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*ZGuWrF0YUEVYk0bg.jpeg" /></figure><p>Reverting git commits is that thing we don’t have to do very often, so we forget how it’s done when you need it the most (a failed Friday deployment, perhaps?)</p><p>Let’s walk through that in this small post, which serves as my own cheatsheet when I need it, and hopefully can serve you too 😄</p><p><strong>Small disclaimer: </strong>This approach will work better when you already have changes merged in your main branch. We will create another commit reverting the changes. If you need to revert something and change the history, you&#39;ll have to use the rebase command instead.</p><h3>Prerequisites</h3><p>I&#39;ll assume the reader already knows how to use the following git commands:</p><ul><li><strong>git log: </strong>shows the commit history. We&#39;ll need this to find the commit hash we want to revert.</li><li><strong>git add/commit/push: </strong>After you revert changes, you&#39;ll commit/push as you normally do.</li></ul><h3>#1 — Using git revert</h3><p>To revert a single commit or an interval of commits, here&#39;s what you&#39;ll do:</p><pre># Find your origin branch, the one you want to revert things from<br>git checkout main <br><br># Use git revert, passing the -n option to generate a single commit <br># USe git log to find the hashs used bellow<br>git revert -n f21306c..e330c04 # OLD_COMMIT..RECENT_COMMIT<br># For a single commit, you don&#39;t need the interval, so `git revert -n f21306c`<br><br># At this point use, git status/diff to confirm the changes you want are there<br>git status # Shows affected files<br>git diff # Shows code changes<br><br># If everything looks right, create a new branch and push:<br>git checkout -b reverted-branch<br>git add .<br>git commit -m &quot;Reverted some commits 🙊&quot;<br>git push origin reverted-branch</pre><p>Note that I&#39;m using the option -n on git revert. Without this option, changes will be committed right away to the working branch.</p><p>I prefer to take things more slowly and be sure of what I&#39;m doing, so this option works best for me.</p><p>Feel free to omit the -n option as needed.</p><h3># 2 — Usando git diff + git apply</h3><p>This is a more manual approach that will get the same result. Usually, git revert will be enough, but sometimes you may have a messier scenario that requires you to review more carefully each change. This approach may be useful in this case:</p><pre># Find your origin branch, the one you want to revert things from<br>git checkout main <br><br># Using git log, find the commit you want to revert<br>git checkout f21306c <br><br># Now, compare the current commit with main. <br># Confirm the changes you want are indeed present<br># If they are not, you may be at the wrong history point<br>git diff main<br><br># If everything matches, save the differences into a patch file.<br>git diff master --full-index &gt; changes.patch<br><br># Now go back to main, and apply the changes<br>git checkout main <br>git apply changes.patch<br>rm changes.patch # Delete the patch file. We don&#39;t want to commit this.<br><br># Now, checkout a new branch and push your commits <br>git checkout -b reverted-branch<br>git add .<br>git commit -m &quot;Reverted some commits 🙊&quot;<br>git push origin reverted-branch</pre><p>I hope this was helpful! If these tips saved a failed Friday deployment for you, drop a comment 🙌</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e9374481a10b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Resilience and Simplicity: The Overlapping Philosophies of SRE and Stoicism]]></title>
            <link>https://medium.com/@tferreiraw/resilience-and-simplicity-the-overlapping-philosophies-of-sre-and-stoicism-a927544fb106?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/a927544fb106</guid>
            <category><![CDATA[software-reliability]]></category>
            <category><![CDATA[stoicism]]></category>
            <category><![CDATA[sre]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Mon, 30 Jan 2023 23:17:50 GMT</pubDate>
            <atom:updated>2023-01-30T23:17:50.193Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Mg4EHGEzdD9SUhJ1cY71Bg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@giamboscaro?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Giammarco Boscaro</a> via <a href="https://unsplash.com/pt-br/fotografias/zeH-ljawHtg?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Some time ago, as I was reading a book on Stoicism, I couldn’t help noticing some strong similarities between the two philosophies — <strong>Stoicism </strong>and <strong>Site Reliability Engineering (SRE).</strong></p><p>Both philosophies strongly emphasize resilience, simplicity, proactive thinking, and personal responsibility.</p><p>Curiously, I could not find any other blog post linking the two philosophies, so here’s my compilation of the similarities I see:</p><h3>Dealing with incidents</h3><p>Let’s compare side by side two quotes.</p><p>First, let’s see a quote from the chapter <a href="https://sre.google/sre-book/being-on-call/">Being On-Call</a> from the 1st SRE Book:</p><blockquote>To make sure that the engineers are in the appropriate frame of mind to leverage the latter mindset, it’s important to reduce the stress related to being on-call. The importance and the impact of the services and the consequences of potential outages can create significant pressure on the on-call engineers, damaging the well-being of individual team members and possibly prompting SREs to make incorrect choices that can endanger the availability of the service. Stress hormones like cortisol and corticotropin-releasing hormone (CRH) are known to cause behavioral consequences — including fear — that can impair cognitive functions and cause suboptimal decision making [[Chr09]](<a href="https://sre.google/sre-book/bibliography#Chr09">https://sre.google/sre-book/bibliography#Chr09</a>).</blockquote><p>Now, let’s look into a quote from <a href="https://www.goodreads.com/book/show/43726564-the-stoic-challenge">The Stoic Challenge</a> (by William B. Irvine). This chapter addresses how to deal with <strong>setbacks, </strong>which can be correlated to the <strong>incidents</strong> in SRE:</p><blockquote>But when a water pipe bursts, the ruptured pipe is only one of the problems that confront you. Besides the problem of not having water where you do want it, you have the much bigger problem of having water where you don’t want it. The unwanted water might flood several rooms, and if the broke pipe is on an upper story, it might cause the lower-story ceiling to collapse. The flooding problem is much more serious than that of the break in the pipe itself. Consequently, when a water pipe bursts, your first response should not be to try to mend the pipe or to go out and buy drinking water so you can make your morning coffee. It should be to turn off the water supply, to prevent your dwelling from getting flooded.<br>In a parallel manner, when you experience a setback, you are faced with not one challenge but two, and the second — <strong>preventing a flood of negative emotions</strong>- is usually more critical than the first.</blockquote><p>To my eyes, both paragraphs are saying the exact same thing. When you experience a setback or if you are handling an incident, preventing the flood of negative emotions (such as fear or anger) is the first thing to do.</p><p><strong>Why</strong>? Simple: Fear and anger may cloud your judgment and cause you to make incorrect/suboptimal decisions that will ultimately make matters worse.</p><p>It amazes me how the first stoics, two millennia ago, figure out so much about human behavior. Many of those concepts were eventually backed up by modern psychology studies (see refs in The Stoic Challenge book), along with research on how certain stress hormones (cortisol) may impair our critical thinking.</p><h3>Embracing simplicity</h3><p>Simplicity is another common topic between the two philosophies and the reason is clear: <strong>simple solutions prevent complex problems</strong>.</p><p>Is important not to confuse being <strong>simple</strong> with being <strong>simplistic</strong>. <strong>Simplistic</strong> means that the solution was simplified to a point it <strong>no longer meets</strong> the requirements. Being simple means we are <strong>meeting the requirements</strong> with <strong>elegance</strong> and avoiding<strong> extra complexity</strong>.</p><p>Quoting from SRE, on the <a href="https://sre.google/sre-book/simplicity/">Simplicity</a> chapter:</p><blockquote>This chapter has repeated one theme over and over: <strong>software simplicity is a prerequisite to reliability</strong>. We are not being lazy when we consider how we might simplify each step of a given task. Instead, we are clarifying what it is we actually want to accomplish and how we might most easily do so. Every time we say “no” to a feature, we are not restricting innovation; <strong>we are keeping the environment uncluttered of distractions</strong> so that focus remains squarely on innovation, and real engineering can proceed.</blockquote><p>Furthermore:</p><blockquote><strong>The price of reliability is the pursuit of the utmost simplicity.</strong></blockquote><p>Simplicity is also very common in the Stoic manuscripts. The goal in the Stoic philosophy is to attain tranquility, and keeping things simple will increase your chances of achieving that goal. One thing that caught my attention in my stoic readings is that if you lose the ability to enjoy simple things, your happiness is doomed. Wanting more things is part of human nature (due to the <a href="https://en.wikipedia.org/wiki/Hedonic_treadmill">hedonic adaptation</a>) and we should try as much as possible to enjoy simplicity.</p><h3>Failure is inevitable</h3><p>In the <a href="https://sre.google/sre-book/introduction/">introduction</a> of the SRE book, you can find that famous cliche phrase:</p><blockquote>Hope is not a strategy.</blockquote><p><a href="https://sre.google/sre-book/embracing-risk/">Embracing risk</a> lives at the core of the SRE philosophy. That is, accepting the fact that failure is inevitable and we should prepare processes to deal with failures when they happen.</p><p>Stoicism, similarly, teaches us to focus on the things we have control over and understand that bad things will eventually happen. See this quote from <strong>Seneca</strong>:</p><blockquote>“Remember that all we have is “on loan” from Fortune, which can reclaim it without our permission — indeed, without even advance notice. Thus, we should love all our dear ones, but always with the thought that we have no promise that we may keep them forever — nay, no promise even that we may keep them for long.” — Seneca</blockquote><p>In summary — both philosophies are similar in the sense that hope is not a strategy. Both also understand that failure is natural and the more prepared we are to deal with them, the better off we will be.</p><h3>Conclusion</h3><p>If you happen to have made it this far, here’s something you should know. I’m an imposter. I don’t have any formal study in philosophy, I’m only an enthusiast on the subject and yet here I am writing about philosophy.</p><p>If you do happen to be knowledgeable in philosophy, please drop a comment. I’d love to get insights on this article from people who studied all of this in-depth 😄</p><p>Nonetheless, this is a thought I’ve been meaning to share for a while now. I believe that knowledge is interconnected and we can draw valuable lessons from several disciplines. For the record, SRE has a chapter saying “<a href="https://sre.google/sre-book/lessons-learned/">Lessons learned from other industries</a>&quot;, which does not mention stoicism directly, but mentions several other concepts from other industries applied in SRE.</p><h3><strong>References</strong></h3><p><strong>Chapters in the SRE book:</strong></p><ul><li><a href="https://sre.google/sre-book/simplicity/">https://sre.google/sre-book/simplicity/</a></li><li><a href="https://sre.google/sre-book/embracing-risk/">https://sre.google/sre-book/embracing-risk/</a></li><li><a href="https://sre.google/sre-book/lessons-learned/">https://sre.google/sre-book/lessons-learned/</a></li></ul><p><strong>Stoicism books I’ve read:</strong></p><ul><li><a href="https://www.goodreads.com/book/show/5617966-a-guide-to-the-good-life">A Guide to the Good Life: The Ancient Art of Stoic Joy</a></li><li><a href="https://www.goodreads.com/book/show/43726564-the-stoic-challenge">The Stoic Challenge</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a927544fb106" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Don’t leave traps in your codebase]]></title>
            <link>https://medium.com/@tferreiraw/dont-leave-traps-in-your-codebase-62bd1840745f?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/62bd1840745f</guid>
            <category><![CDATA[managing-technical-debt]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[technical-debt]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Sun, 08 Jan 2023 20:24:29 GMT</pubDate>
            <atom:updated>2023-01-09T10:24:10.633Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FUFY0a_9GAom37v4GwKaNA.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@manuschwendener?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">manu schwendener</a> on <a href="https://unsplash.com/photos/zFEY4DP4h6c?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>If you don’t know me personally, here’s something about me: <strong>I’m an awfully clumsy person</strong>. If there is a glass in the corner of the table, I’ll eventually knock it off to the floor. It’s not a matter of <strong>IF,</strong> but <strong>WHEN</strong>. I’m sure I’ll break stuff eventually if I have the chance to 😂</p><p><strong>Ok, how does this relate to coding, then?</strong></p><p>In my life, I developed a system to help me with my clumsy nature. I don’t leave glasses in the corner of tables, I don’t leave things in places that I know I’ll break/damage somehow.</p><p>I ended up learning the same precautions can be applied in my work/career to avoid breaking stuff — for myself and for others.</p><p>Here are a few common traps we leave in our code and how to overcome them</p><h3>Low test coverage</h3><p>Low test coverage in software means that not all parts of the code are being tested in an automated manner. This can have several negative consequences:</p><ol><li><strong>Bugs and defects may not be detected</strong> before affecting the real world</li><li>It is difficult to determine the<strong> quality and reliability</strong> of the software</li><li>It is difficult to <strong>make changes</strong> to the code, as you can’t be sure of what will break without running extensive manual tests.</li><li>Extra difficulty in <strong>finding the root cause of problems</strong>, which may affect the team’s ability to fix issues in a timely manner.</li></ol><p>I consider low test coverage a trap in the codebase because similar to my personal issue of knocking glasses out of the table, it’s not a matter of IF this will be a problem. <strong>It’s a matter of WHEN</strong>.</p><p>In conclusion, a low test coverage <strong>decreases the quality and reliability of the software</strong> and makes <strong>maintenance and improvement harder</strong> over time.</p><h3>Missing documentation</h3><p>A huge part of my day-to-day as a software engineer is conveying information from one place to another. Sometimes is moving information into my brain, or vice versa.</p><p>When we are working actively on a project, we have a lot of information fresh and easily accessible in our minds. As time passes, we will certainly forget a good portion of that information.</p><p>If we do not make a conscious effort to document information in the correct channels, we are causing problems for your company. Quoting <strong>Bob Martin</strong>, author of the<strong> Clean Coder</strong>, one of the first things professionals need to have in mind is <strong>“to not cause problems”</strong>.</p><p>Documenting information properly is part of our job and part of our responsibility as professional software engineers.</p><p>Aside from that, here are other problems that missing documentation can cause:</p><ul><li><strong>It can be difficult for new team members to understand the code and become productive</strong></li><li><strong>Difficulty to maintain the code: </strong>similar to the lack of unit tests mentioned above, no documentation means that whoever is going to make changes in the code will have to figure it out on their own — and this will take time.</li><li><strong>It can be difficult to use the software: </strong>Without proper documentation, how are you supposed to know what the code is supposed to do/ or even capable to do?</li><li><strong>Different folks will work in this code in the future: </strong>as time passes, the author of a project may not be involved anymore. This is actually the most common scenario. Documenting things in time ensure that people won’t take crucial information with them when they leave.</li></ul><h3>Over-complicated code</h3><p>You might get away with missing documentation if you write code that is simple, concise, and easy to read.</p><p>Well-written code can serve as documentation, so be sure to make your code as simple and as readable as possible.</p><p>Here’s an example of an over-complicated code (with high cyclomatic complexity) and how we can fix it:</p><pre>def calculate_discount(price, customer_type, item_type):<br>    if customer_type == &#39;regular&#39;:<br>        if item_type == &#39;clothing&#39;:<br>            return 0.1 * price<br>        elif item_type == &#39;furniture&#39;:<br>            return 0.2 * price<br>        else:<br>            return 0.15 * price<br>    elif customer_type == &#39;premium&#39;:<br>        if item_type == &#39;clothing&#39;:<br>            return 0.2 * price<br>        elif item_type == &#39;furniture&#39;:<br>            return 0.3 * price<br>        else:<br>            return 0.25 * price<br>    else:<br>        if item_type == &#39;clothing&#39;:<br>            return 0.15 * price<br>        elif item_type == &#39;furniture&#39;:<br>            return 0.25 * price<br>        else:<br>            return 0.2 * price </pre><p>This can be refactored into the following code, which is a lot simpler to read and understand:</p><pre> def calculate_discount(price, customer_type, item_type):<br>    discounts = {<br>        (&#39;regular&#39;, &#39;clothing&#39;): 0.1,<br>        (&#39;regular&#39;, &#39;furniture&#39;): 0.2,<br>        (&#39;regular&#39;, &#39;other&#39;): 0.15,<br>        (&#39;premium&#39;, &#39;clothing&#39;): 0.2,<br>        (&#39;premium&#39;, &#39;furniture&#39;): 0.3,<br>        (&#39;premium&#39;, &#39;other&#39;): 0.25,<br>        (&#39;other&#39;, &#39;clothing&#39;): 0.15,<br>        (&#39;other&#39;, &#39;furniture&#39;): 0.25,<br>        (&#39;other&#39;, &#39;other&#39;): 0.2<br>    }<br>    <br>    return discounts[customer_type, item_type] * price</pre><h3>“Traps” == Technical Debt?</h3><p>Technical debt refers to the accumulation of shortcuts, hacks, and unfinished work that will eventually cause problems for the team, like missing deadlines, poor code quality, more bugs, and taking a longer time to finish projects.</p><p>Just like financial debt, technical debt accumulates interest and becomes really expensive over time.</p><p>All the “<strong>traps</strong>” mentioned above can be considered technical debt. It’s normal for teams to deal with technical debt, as sometimes we have to <strong>make tradeoffs to finish projects</strong>.</p><p>It is important though to not lose track of the technical debt and allocate resources to clean it up on a regular basis — which is important for the <strong>team’s efficiency in the long run</strong>.</p><h3>Conclusion</h3><p>I have used this approach for years in my career (and personal life) and “<strong>not leaving glasses on the corner of the table</strong>”, figuratively or not, has been paying off really well for me and helping me avoid all sorts of problems.</p><p>Another way to think about this is by making an intersection with the world of cooking. There is a french expression “<a href="https://en.wikipedia.org/wiki/Mise_en_place">Mise en place</a>”, which means putting everything in order/in the correct place to be able to work smoothly. That’s a way to think about coding too: everything should be in the correct place.</p><p>Thank you for making it this far in this peculiar thought 🙌🙏 I hope it was helpful!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=62bd1840745f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Keeping sane when handling timezones — a quickstart guide with python]]></title>
            <link>https://medium.com/@tferreiraw/keeping-sane-when-handling-timezones-a-quickstart-guide-with-python-970468591da?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/970468591da</guid>
            <category><![CDATA[python]]></category>
            <category><![CDATA[timezone]]></category>
            <category><![CDATA[datetime]]></category>
            <category><![CDATA[time]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Tue, 08 Nov 2022 10:38:35 GMT</pubDate>
            <atom:updated>2022-11-08T10:38:35.341Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>Keeping sane when handling timezones — a quickstart guide with python</strong></h3><figure><img alt="Photo by &lt;a href=”https://unsplash.com/@jontyson?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Jon Tyson&lt;/a&gt; on &lt;a href=”https://unsplash.com/s/photos/clocks?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;" src="https://cdn-images-1.medium.com/max/1024/1*8f399rq3ZHetn1tA_YHBiw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@jontyson?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Jon Tyson</a> on <a href="https://unsplash.com/s/photos/clocks?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Handling time zones can be quite maddening at first. If you work developing software, chances are you’ll have to deal with timezones eventually, primarily if your project is used in multiple locations (states, countries…).</p><p>It’s really confusing for the human brain to compare dates and times in different time zones. If you ever took a flight to a destination at a different timezone, you have experienced how confusing it can be.</p><p>This short article aims to give you a quick start with the terminology, most used methods, and some tips and tricks.</p><h3>Terminology</h3><ul><li><strong>Timezone</strong>: From Wikipedia, “A time zone is an area which observes a uniform standard time for legal, commercial and social purpose. All time zones are defined as offsets from Coordinated Universal Time (UTC).”</li><li><strong>Naive date time </strong>object<strong>:</strong> when a DateTime object does not contain timezone information, we call it “naive”, e.g. 2022–10–13 8:00. This data time has some limitations, as you won’t be able to run certain calculations without the timezone info.</li><li><strong>Aware date time object:</strong> if you have a DateTime object and the timezone info e.g. 2022–10–13 8:00 (GMT-3:00 BRT), then you can run calculations and easily convert this to other timezones.</li><li><strong>Time delta</strong>: a time period, like “4 hours and 15 minutes”.</li></ul><h3>Looking at a few examples</h3><p>Flights are a perfect example to work on: you depart from a city that has a different timezone from the destination. Let’s see what that looks like:</p><p>Here’s a summary of each step:</p><ul><li><strong>1-timezones.py: </strong>Importing the modules we need in the rest of the code</li><li><strong>2-timezones.py: </strong>Creating a new data class named <strong>City </strong>to save the city’s name and time zone info</li><li><strong>3-timezones.py: </strong>Another data class for <strong>flight</strong> information. We’ll need the origin, destination, flight duration, and departure time. Note we’ll also need some calculation methods to display the arrival date at the correct timezone.</li><li><strong>4-timezones.py: </strong>Putting everything together: initialize City objects for origin and destination, along with a <strong>Flight.</strong></li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/44c7ad71e1a44411b9fab401801a7a55/href">https://medium.com/media/44c7ad71e1a44411b9fab401801a7a55/href</a></iframe><p>This code will output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/918/1*TJasgJtI5gQ334NcEU-HVA.png" /></figure><p>Note the flight took 4h15, but the local time when you left was <strong>16:15</strong>, and <strong>19:30</strong> when you arrived 🤯</p><h3>Databases</h3><p>You’ll probably want to store date-time objects in the database at some point. When that happens make sure you save the timezone information as well, so you can adequately convert when needed.</p><p>Example in Postgres:</p><pre>select created_at at time zone &#39;america/los_angeles&#39;<br>from users;</pre><h3>A few gotchas to avoid</h3><p>Timezones are more than a single offset between UTC and the local time. They store information about a geographical area that might have had multiple offsets over the course of history.</p><p>Take <strong>Daylight Saving Time</strong> for example. The offset changes in a geographical area twice a year.</p><p>Gladly, <strong>pytz</strong> handles this for us, we have to make sure to use the correct method:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FpdJUQH_so8usG5yAa0ZwA.png" /></figure><p>See the offset is incorrect for 2 reasons:</p><ul><li>Daylight Saving Time <a href="https://www.timeanddate.com/time/change/usa/new-york">ended in this region</a> on 2022–11–06. The offset should be <strong>UTC-4</strong>, not <strong>UTC-5.</strong></li><li>There is a 4-minute difference; As we mentioned earlier, the timezone represents a geographical area that might’ve had multiple timezones over time. If we don’t localize the date correctly, <strong>pytz </strong>won’t know the correct offset to use.</li></ul><p>Do this instead:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wh9-Q5erj85VYTcsie-E7g.png" /></figure><p>Note the offset is correct when we use the <strong>localize </strong>method. Plus, the 4-minute difference is gone 🎉.</p><h3>Conclusion</h3><p>As long as you have a reference to the correct timezone and you localize/convert from one to another, python should manage timezones marvelously for you. Also, be aware to use the correct <strong>localize </strong>method from <strong>pytz</strong> to ensure you get the correct offset 🎉</p><p>A few references:</p><ul><li><a href="https://popsql.com/learn-sql/postgresql/how-to-convert-utc-to-local-time-zone-in-postgresql">https://popsql.com/learn-sql/postgresql/how-to-convert-utc-to-local-time-zone-in-postgresql</a></li><li><a href="https://docs.python.org/3/library/datetime.html">https://docs.python.org/3/library/datetime.html</a></li><li><a href="https://pytz.sourceforge.net/">https://pytz.sourceforge.net/</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=970468591da" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Make it easier for people to help you]]></title>
            <link>https://medium.com/@tferreiraw/make-it-easier-for-people-to-help-you-d775358e7482?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/d775358e7482</guid>
            <category><![CDATA[communication]]></category>
            <category><![CDATA[mentoring]]></category>
            <category><![CDATA[communication-skills]]></category>
            <category><![CDATA[social-skills]]></category>
            <category><![CDATA[helping-others]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Mon, 03 Oct 2022 22:43:42 GMT</pubDate>
            <atom:updated>2022-10-04T12:31:34.559Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AgROH0rV2YHrUnYzPZu4aQ.jpeg" /></figure><p>This is a tiny thought that has been in the back of my mind for years now. I think it is an incredibly simple concept with a huge potential to get any person to improve their lives and careers.</p><p>Throughout my career, I’m very grateful to have had <strong>incredibly smart people</strong> helping me out and I could learn a LOT from them.</p><p><strong>Asking for help</strong>, though, is not something that comes naturally to some people and I like to think that <strong>asking for help is a skill</strong>.</p><p>Just like <strong>any skill</strong>, any person can master the ability of asking for help and unblocking a huge potential to get valuable information from smart people.</p><p>Let’s break this down into <strong>3 simple steps</strong>:</p><h3><strong>1 — Give enough context when asking for help</strong></h3><p>Let’s take a look at this example:</p><blockquote><strong>Person 1</strong>: Can someone help me with this thingy?</blockquote><p>And another one for comparison:</p><blockquote><strong>Person 2</strong>: Can someone help me with this thingy?</blockquote><blockquote><strong>TL;DR</strong>: I’m trying to do <strong>X </strong>but Y is not working out for me. Can someone give me a hand?</blockquote><blockquote><strong>Full context:</strong></blockquote><blockquote>I’m working at X, which is part of the project Y. Part of the task involves getting Z done, which is exactly the piece I am having issues with.</blockquote><blockquote>I have tried already:</blockquote><blockquote><strong>Option A:</strong> Didn’t work because this and that…</blockquote><blockquote><strong>Option B:</strong> Didn’t work because this and that and that…</blockquote><blockquote><strong>Option C:</strong> Could not test it because this and that.</blockquote><blockquote>After testing those options and reading through the documentation, I am now blocked and not sure yet how to move forward. I would appreciate if any of you had some clues on how to proceed.</blockquote><blockquote>Thank you!</blockquote><p>Now, which person do you think will get a faster reply and will work their way out of the issue faster?</p><p>Certainly <strong>Person 2</strong> for a few reasons:</p><ul><li>There is already a lot of <strong>context</strong> in the message. Someone familiar with that might <strong>easily reply</strong> with <strong>valuable information</strong>.</li><li>It shows that <strong>Person 2 </strong>is already very organized and helping this person could be very simple and fast.</li></ul><p>The issues I see with the approach from <strong>Person 1:</strong></p><ul><li>It creates friction to get help. It requires at least another reply to get the full context, so it needs one more interaction. Something like “I need help”, “Sure, what’s up?”, “Oh, I’m having this and that issue”. See? It takes longer and does not work in favor of asynchronous communication.</li><li>It may give the impression that you are not so well organized, which may give the impression that you don’t value and respect your coworkers time.</li></ul><p>In summary, in our busy day to day work, if you can reduce the<strong> friction</strong> you create for people to help you, you’ll get better and faster answers and therefore you have better changes at <strong>excelling</strong> at what you do.</p><p>The most valuable lesson in this step is:</p><ul><li>Make sure you <strong>value</strong> and<strong> respect</strong> your coworkers time.</li><li><strong>Asynchronous communication</strong> is key, specially in a remote work environment. Giving the full context will ensure people can <strong>respond efficiently</strong>, even if they work in different timezones.</li></ul><h3>2 —Be proactive in asking for feedback</h3><p>Sometimes, specially when we create things, we may be afraid of asking for feedback, dreading that people might find problems in our so-precious sollution.</p><p>Not asking for feedback is something that can delay your career improvement for a few reasons:</p><ul><li>People <strong>might not</strong> proatively give you feedback. <strong>Giving feedback is hard</strong>. It requires attention, empathy, time and a lot more. If you don’t ask, people might simply not tell you something is wrong.</li><li>If you don’t ask for feedback, you’ll miss valuable insights from people that are possibly more experienced than you, and/or have different perspectives. Can you image the <strong>amount of issues</strong> that <strong>early feedback</strong> can save you from in the future?</li></ul><h3>3 — Be polite and light-hearted</h3><p>One thing to bear in mind is that other people are living their own live, managing their own problems.</p><p>The best thing I can recommend is that the best way to ask for help is to:</p><ul><li><strong>Be polite</strong>. Don’t assume that other people <strong>HAVE </strong>to help you. They might be dealing with other issues or not be available at the moment for any reason.</li><li><strong>Be light-hearted</strong>: Life is hard enough. Why not write some upbeat messages that will lighten the mood and make the interaction a lot easier?</li></ul><h3>One last trick when asking for help</h3><p>If you are asking for help to an experienced person, they might be tempted to give you a LOT of context and a lot of information.</p><p>That’s because <strong>experienced people</strong> don’t want to <strong>steer you in the wrong direction</strong>. Also, they understand they previous experience might have worked for certain problems, but they understand there is no silver bullet. No solution will solve all sorts of issues.</p><p>What to do in this case then?</p><p><strong>Ask:</strong> If you had these parameters, what would <strong>you</strong> do in this situation?</p><p>This is simple question that can have marvelous results. That answer will push the person to think about how they would solve it themselves, using all their <strong>previous experience</strong>.</p><p>You certainly <strong>don’t need to follow the recommendation</strong> exactly, but their answer might open your mind to ask better questions and understand their reasoning.</p><p>This question might also tap in their <strong>innarticulate knowledge</strong>:</p><blockquote>“We know more than we’re able to explain that we know. And I call this inarticulate knowledge — the knowledge that I’m not able to articulate to somebody. And I have inarticulate knowledge about a lot of things, including other people. I could have tacit knowledge of why I trust somebody that I couldn’t explain to you. If you asked me to give you specific things, I wouldn’t be able to point to that, “Oh, there’s that one time when we were hanging out together,” because it’s probably not any one particular thing. It’s probably a series of things, call it a gut feeling. I just have that. And I have the same thing for mistrust. Right? And I <strong>think that this kind of tacit knowledge and articulate knowledge is undervalued in our society. It’s undervalued because we always want to be able to explain the science and give the hard reasons for it. But a lot of life doesn’t work like that</strong>.”</blockquote><blockquote>Entrepreneur, author, and educator Luke Burgis joins me for a deep dive on the René Girard and mimetic desire, different forms of knowing, and living a meaningful life. (<a href="https://click.convertkit-mail4.com/8ku5574ekghoh0009n9b5/g3hrz855h5he90kpz8ir/aHR0cHM6Ly9mcy5ibG9nL2tub3dsZWRnZS1wcm9qZWN0LXBvZGNhc3QtdHJhbnNjcmlwdHMvbHVrZS1idXJnaXMtMTM4Lw==">read the transcript</a>)</blockquote><h3>Conclusion</h3><p><strong>Life is complicated</strong>. The more we can learn from other people, more mistakes we’ll avoid in our future.</p><p>There are simple ways to ask for help in a way that significantly improves your chances of getting that <strong>life changing information</strong> you are looking for.</p><p>I hope you liked this tiny thought, please reach out if you have any questions or insights in the subject.</p><p>Thank you for reading!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d775358e7482" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why is it so important to use up-to-date software versions?]]></title>
            <link>https://medium.com/@tferreiraw/why-is-it-so-important-to-use-up-to-date-software-versions-d69c7628f1ec?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/d69c7628f1ec</guid>
            <category><![CDATA[owasp-top-10]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[log4j]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Thu, 21 Jul 2022 12:18:28 GMT</pubDate>
            <atom:updated>2022-07-21T12:18:28.503Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/596/0*wtMiM9wtrk_IGVOb.png" /></figure><p>Using outdated software versions may bring <strong>severe consequences</strong> to a product, from <strong>security problems</strong> to <strong>increased complexity</strong> in its <strong>maintenance/evolution</strong>. This article will explain how software versioning works and how we can avoid these problems.</p><h4>Understanding the life cycle</h4><p>Most software we use every day has some sort of <a href="https://en.wikipedia.org/wiki/Product_life-cycle_management_(marketing)">life cycle</a>. From operating systems like Android, iOS, and Windows to smaller components and libraries that compose our applications.</p><p>The life cycle is important for <strong>evolving software and applications</strong>, that means, life cycles provide the <strong>ability to add new features</strong> and make architectural changes in applications, following the market’s new technologies and trends.</p><p>This information is usually available on the releases page of any given application/library/framework. Let’s take for example the <a href="https://www.djangoproject.com/download/">Django Framework</a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/820/0*vGbyRkzFnEjdhShL.png" /></figure><h4>Understanding Semantic Versioning</h4><p>To navigate in the software development world, we need to understand the most commonly used versioning guideline:<strong> </strong><a href="https://semver.org/"><strong>Semantic Versioning</strong></a>. Quoting from the official website:</p><blockquote>Given a version number MAJOR.MINOR.PATCH, increment the:</blockquote><blockquote>1. MAJOR version when you make incompatible API changes,<br>2. MINOR version when you add functionality in a backwards compatible manner, and<br>3. PATCH version when you make backwards compatible bug fixes.</blockquote><p>Let’s take a look at some examples of what this means in practice:</p><ul><li>Given we have a current version of <strong>2.8.1</strong></li><li>If we update it to <strong>2.8.2, </strong>this means we fixed something and backward compatibility is maintained.</li><li>If we update it to <strong>2.9.0, </strong>this means there are new features available and they are compatible with the older features (meaning: it shouldn’t break anything)</li><li>If we update it to <strong>3.0.0, </strong>this means we have new features and bug fixes, but also <strong>breaking changes</strong>, which are changes not compatible with the previous version.</li></ul><p>In our day-to-day, we need to keep an eye out when updating versions to avoid having problems with <strong>breaking changes </strong>(explained below).</p><h4>Dealing with Breaking Changes</h4><p>Over the life cycle of a given piece of software, there will be times when an update will <strong>no longer have compatibility</strong> <strong>with previous versions</strong>, which requires the end user to make adjustments in order to update to newer versions.</p><p>From the maintainer&#39;s standpoint, <strong>backward compatibility is a quite challenging and complex problem</strong>. This way, but choosing to drop compatibility with previous versions, maintainers will have more freedom and capacity to create new features and enhancements, without worrying about legacy parts of the code. An excellent example of this is <a href="https://reactjs.org/docs/faq-versioning.html#commitment-to-stability">React’s Versioning Policies</a>.</p><h4>Long-term support (LTS)</h4><p><strong>Long-term support</strong> is a period in the software life cycle where the maintainers will continue working actively on the product, making improvements and bug fixes.</p><p>If a critical problem is found in an <strong>LTS </strong>version, it is expected that the issue will be fixed by the maintainers with a new version.</p><p>Using <a href="https://www.djangoproject.com/download/">Django</a>’s life cycle as an example we can see that version 2.2 will have support until the beginning of 2022. After that, the new LTS version will be <strong>3.2.</strong> Having this in mind is crucial for planning our own updates, especially when the new version contains <strong>breaking changes.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*lVE_ZVV4BTpyQ5OI.png" /></figure><h4>How different software components relate to each other</h4><p>It is interesting to note that many software components will be related in some way. Let’s take <a href="https://www.python.org/doc/sunset-python-2/">python 2</a> as an example, which has been <strong>completely discontinued</strong> in January 2020.</p><p>This means that even if security problems are found in python 2, <strong>these problems will not be fixed. </strong>This is why it is so important to update to the LTS versions as soon as possible.</p><p>As soon as python 2 was discontinued, many python libraries like <strong>Django</strong> and <strong>Flask </strong>started dropping support for Python 2, along with many other libraries.</p><p>Note the “cascade effect”: if you are using a library in a version that is no longer in LTS, all related/depending libraries will also drop support for that.</p><h4>What happens if I don’t update?</h4><p>As we can see <a href="https://www.cvedetails.com/,">cvedetails</a> (security vulnerability data source), new problems may be found at any time.</p><p>Given that, if we are using an <strong>outdated software version</strong> that is no longer in <strong>Long-term support</strong>, we will <strong>not </strong>have an available patch to fix the security vulnerabilities.</p><p>We might have the option to update to a newer version, but if there are <strong>breaking changes,</strong> this will make it a lot harder to update to the newer versions, as we have to adapt some parts of our own software before updating.</p><h4><strong>Case study: Log4j vulnerability in 2021</strong></h4><p>It can get a little abstract to speak about the importance of using up-to-date software versions looking only to the future. For that reason, let’s take a look at a recent case:</p><p>In December 2021, a <a href="https://www.cve.org/CVERecord?id=CVE-2021-44228">severe security vulnerability</a> was found in <strong>Log4j</strong>, a logging tool for <strong>Java</strong>. This vulnerability allowed access to a remote server, simply injecting a command in the forms, headers, or URLs.</p><p>The Elastic Stack was quite affected by this vulnerability and on this page <a href="https://www.elastic.co/support/eol">https://www.elastic.co/support/eol</a>, we can see which versions no longer offer support. Note that:</p><p><strong>Versions 7.x</strong> are the newest versions with active support, so they will be updated accordingly. Version <strong>6.8.x </strong>had support until 2022, so in December of 2021, it still had updates.</p><p>This means that any person using older versions like <strong>5.x</strong> will have a lot of work to update: they’ll first have to make adjustments for the breaking changes, then update to <strong>7.x</strong>, where the fix is available. That’s a lot of work.</p><p>Speaking of a <strong>critical security vulnerability</strong>, there is very little time to lose, so the best scenario is to always be using up-to-date versions to be able to quickly update and be secure.</p><h4>Other references</h4><p><a href="https://owasp.org/">OWASP</a> is an organization that works to map the main security vulnerabilities in the web and make them available for all the software development community, which ensures we’ll be all building secure software.</p><p>The project “Owasp Top 10” maps the 10 principal security vulnerabilities and item #6 of the list speaks directly to the fact that using outdated components is a security risk. Check the full list at:</p><ul><li><a href="https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/">https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d69c7628f1ec" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Performing load tests with Python + Locust.io]]></title>
            <link>https://medium.com/@tferreiraw/performing-load-tests-with-python-locust-io-62de7d91eebd?source=rss-18a8fd20a75c------2</link>
            <guid isPermaLink="false">https://medium.com/p/62de7d91eebd</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[load-testing]]></category>
            <category><![CDATA[sre]]></category>
            <dc:creator><![CDATA[Thiago Ferreira]]></dc:creator>
            <pubDate>Tue, 21 Jun 2022 11:27:25 GMT</pubDate>
            <atom:updated>2022-06-21T11:28:38.499Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/996/0*idwTi5T-46JSocHK.png" /></figure><p>In the context of high performance and availability systems, load tests are a type of performance test where we check how a determined part of the system will handle many simultaneous users at the same time.</p><h3>When should I use load tests?</h3><p>Load tests will come in handy in many ways:</p><ul><li>When making performance improvements, we can check if the improvements are truly effective.</li><li>When making decisions about a particular tech stack, load tests can be used to compare multiple approaches to the same problem and determine which works best.</li><li>Estimate how many simultaneous users are supported by the given system.</li><li>Find bottlenecks, that is, components of the system that will take too long to respond and affect the overall response time and user experience.</li></ul><h3>Locust.io</h3><p><strong>Locust.io </strong>is an open-source tool created to design and run load tests. The user behavior is defined by pure python code, which makes it easily customizable and extensible for many use-cases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/0*JMaFyiYSzqwhsDzJ.png" /></figure><h3>Setting up the load test</h3><p>It is possible to run this sample project on your local machine or even deploy it to a cloud provider of your choice. Running that in a cloud provider will provide more accurate results since it will be similar to a real production environment. To get started, we’ll need these two repositories:</p><ul><li><a href="https://github.com/thiagoferreiraw/locust-stress-test">locust-stress-test</a>: Implements some tests using the <strong>locust.io</strong> tool. This is where we define the user behavior, like what pages it will access and the frequency.</li><li><a href="https://github.com/thiagoferreiraw/django-todo-list">django-todo-list</a>: A simple API built in python/Django that will be our target in the load tests.</li></ul><p>Locust code will look like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6276f6344ba1d90bcffbe9b9eae89ec1/href">https://medium.com/media/6276f6344ba1d90bcffbe9b9eae89ec1/href</a></iframe><p>Here we are defining the user behavior:</p><ul><li>Get a list of tasks using GET /tasks/</li><li>Create new tasks using POST /tasks/</li><li>Each user will wait between 1 and 3 seconds between requests.</li><li>The number of requests in the list of tasks is 5x greater than the requests to create new tasks. Since on many websites the user will probably read a lot more than write, this is a simulation very close to reality.</li></ul><h3>Setting up the environment</h3><p>It’s preferable to run the load test in a cloud provider (AWS, GCP, DigitalOcean, etc) to have accurate results with the reality, since this way we avoid having our local machine interfering with the results. To do so, I chose the following resources for this example:</p><ul><li>Postgres Database, <a href="https://www.digitalocean.com/products/managed-databases">managed by DigitalOcean</a>, with 1vcpu + 1GB RAM.</li><li>Application layer using <a href="https://www.digitalocean.com/products/app-platform/">App Platform</a>, with 1vcpu + 1GB RAM</li></ul><h3>Running the test</h3><p>The instructions to install and run the tests are detailed in the repository <a href="https://github.com/thiagoferreiraw/locust-stress-test">locust-stress-test</a>, but in summary, we need to run:</p><pre>poetry run locust --host=http://localhost:8000</pre><p>After that, open the web interface displayed in your terminal, set up the test parameters then click “Start Swarming”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/388/0*h0a2YIiaZgIoBbAx.png" /></figure><h3>Results and conclusions</h3><p>Find below the complete report provided by <strong>Locust.io. </strong>Here are some observations:</p><ul><li>Until around 160 simultaneous users, we were having around 60 requests per second and the response time was very acceptable for this context (95% of requests finished in less than 400ms)</li><li>The definition of what is an acceptable response time will vary depending on the context. Usually, we seek to have a <a href="https://blog.avenuecode.com/how-to-determine-a-performance-baseline-for-a-web-api">response time lower than 300ms for APIs in general</a>, but keep in mind this might change depending on the context of each system.</li><li>After passing 160 simultaneous users, note the number of requests per second remains the same (60rps), but the response time increased a lot. This way, each user started having slower responses.</li><li>In summary, with the available computing resources, we could serve around 160 simultaneous users with 60rps and a response time lower than 400ms. To increase these numbers, we would need more computing resources or make performance adjustments in the code. We could also add cache layers such as <strong>Memcached</strong> or <strong>Redis</strong> where it makes sense.</li></ul><p>Check out the full report:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*yqdUbz8VqM0qU-Yq.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-lB4bOWt-_0z_S7D.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Fz_UwCnrU4vi08Bz.png" /></figure><h3>Understanding CPU and memory usage</h3><h4>Application layer</h4><p>In our application layer, we see the CPU usage growing until it reached 100%. In a way, it’s a good sign that CPU usage is ramping up. This means our application server is well configured and it is not leaving idle resources.</p><p>On the other hand, since our CPU usage is getting to 100%, this also means we need more computing resources.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*lykTYhcS32AvqCB6.png" /></figure><h4>Database layer</h4><p>We can also see in the database stats that we have a high CPU usage. This shows that the database computing resources need to be increased. To do so, we have a few approaches:</p><ul><li>Increase the computing resources for the database (+CPU, +Memory)</li><li>And/Or create read-only replicas, in a way we’ll have separated instances for reading and writing in the database.</li><li>And/Or add a cache layer (Redis, Memcached, etc) where possible to decrease the database load.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*vJklwruaxbNWEtSg.png" /></figure><h4>One step at a time</h4><p>When performing load tests and improving performance, it is important to make small changes, one at a time. This way we can verify how much a given change affected the results. In the screenshot below, we can see the exact point where I changed a configuration and the response time improved a lot:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*pV8eiai0U0FR2Lpe.png" /></figure><p>Combining small changes with monitoring (results and computing resources), we can understand how our system behaves under stress and adjust accordingly.</p><p>Additionally, this is a great usage of the <a href="https://medium.com/whatsgooddev/princ%C3%ADpio-da-falseabilidade-em-tecnologia-como-tomar-decis%C3%B5es-mais-assertivas-9fbbff9be6fc">Falsifiability principle</a> in technology, which helps us make better and more assertive decisions about our infrastructure.</p><h4>References</h4><ul><li><strong>Repositories with sample code</strong>: <a href="https://github.com/thiagoferreiraw/locust-stress-test">locust-stress-test</a> e <a href="https://github.com/thiagoferreiraw/django-todo-list">django-todo-list</a></li><li><strong>Setting it up on DigitalOcean</strong>: <a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-django-to-app-platform">How To Deploy a Django App on App Platform</a></li><li><a href="https://itnext.io/will-it-scale-lets-load-test-geohashing-on-dynamodb-fbdc612d9ec3">Performance Testing vs. Load Testing vs. Stress Testing</a></li><li><a href="https://www.blazemeter.com/blog/performance-testing-vs-load-testing-vs-stress-testing">Will it scale? Let’s load test geohashing on DynamoDB</a></li><li><a href="https://blog.avenuecode.com/how-to-determine-a-performance-baseline-for-a-web-api">How to Determine a Performance Baseline for a Web API</a></li><li>🇧🇷 PT-BR Version: <a href="https://medium.com/whatsgooddev/como-fazer-testes-de-carga-com-python-locust-io-55ec6ae841b">Como fazer testes de carga com Python + Locust.io</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=62de7d91eebd" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>