<?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: Mario Fernández</title>
    <description>The latest articles on DEV Community by Mario Fernández (@sirech).</description>
    <link>https://dev.to/sirech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F353907%2Fcac5bd7b-69c6-45c2-97b7-2e7b90024642.jpg</url>
      <title>DEV Community: Mario Fernández</title>
      <link>https://dev.to/sirech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sirech"/>
    <language>en</language>
    <item>
      <title>Book Review: Software Engineering at Google</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Sun, 10 Dec 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/book-review-software-engineering-at-google-2pci</link>
      <guid>https://dev.to/sirech/book-review-software-engineering-at-google-2pci</guid>
      <description>&lt;p&gt;&lt;a href="///static/f4c6ee677d7af7e12fa92a96fd1ff60c/ac471/cover.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oxmzTTbq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hceris.com/static/f4c6ee677d7af7e12fa92a96fd1ff60c/ac471/cover.jpg" alt="Software Engineering at Google" width="381" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://abseil.io/resources/swe-book"&gt;Software Engineering at Google&lt;/a&gt; is, unsurprisingly, a book about how Google engineers develop software.&lt;/p&gt;

&lt;p&gt;For years, Google has captivated the curiosity of software engineers. After all, they built things like &lt;a href="https://research.google/pubs/pub27898/"&gt;Bigtable&lt;/a&gt;, &lt;a href="https://research.google/pubs/pub39966/"&gt;Spanner&lt;/a&gt;, and many others.&lt;/p&gt;

&lt;p&gt;However, this book delves behind the scenes, emphasizing three key areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Processes&lt;/li&gt;
&lt;li&gt;Tools&lt;/li&gt;
&lt;li&gt;Culture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s cover each, as I think some parts are more insightful than others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remember that You Aren’t Google
&lt;/h2&gt;

&lt;p&gt;Keep in mind one thing while reading this book: Most companies don’t have the problems, the scale, or the resources that Google has. For most people, many of the solutions presented in this book won’t apply.&lt;/p&gt;

&lt;p&gt;I’ve only realized this after I joined a BigTech company. It’s hard to picture the difference in scale until you see it firsthand. For instance, I find &lt;a href="https://newsletter.pragmaticengineer.com/p/stacked-diffs"&gt;stacked diffs&lt;/a&gt; quite useful. However, I think they work in a very specific environment, and I’ve got ex-colleagues who just couldn’t imagine that being useful. And that’s fine.&lt;/p&gt;

&lt;p&gt;Anyways, back to the book.&lt;/p&gt;

&lt;h2&gt;
  
  
  Processes: Making it Work At Scale
&lt;/h2&gt;

&lt;p&gt;Google is renowned for its massive mono repo. What you do can affect a lot of other engineers, thus they developed a strong culture around reviews. They have systems around who can review which technology or aspect that’s quite interesting. In a past gig, they copied the system with terrible results. Beware of copying anything if you don’t have the necessary resources.&lt;/p&gt;

&lt;p&gt;Another unique area is testing. At this size, running tests becomes kind of a probabilistic exercise. Any test that can be flaky will become so if it runs millions of times. Google is also famous for having popularized the &lt;a href="https://hceris.com/book-review-site-reliability-workbook/"&gt;SRE&lt;/a&gt; role. However, operations aren’t covered in this book that much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools: The Secret Weapon
&lt;/h2&gt;

&lt;p&gt;Tooling is my favorite part of this book. Developer tools that seamlessly work are extremely satisfying. Also, this is the last thing a small company should try to copy. Internal tools are challenging to nail, and the incentives skew against them.&lt;/p&gt;

&lt;p&gt;Moreover, it’s an existential thing at a certain scale. A mono repo as gigantic as Google’s needs top-notch tooling. Otherwise, you can’t even browse files properly. The same goes for navigating code. You need a supercharged &lt;code&gt;grep&lt;/code&gt; that works quickly and reliably across the whole repo.&lt;/p&gt;

&lt;p&gt;I really like the chapter that touches on large-scale changes. A change across hundreds or thousands of files feels magical when it actually works.&lt;/p&gt;

&lt;p&gt;Interestingly, CI/CD is pretty vanilla at Google. Granted, it seamlessly works with much bigger volumes of changes. Other than that, it doesn’t do anything out of the ordinary. Check this &lt;a href="https://hceris.com/modernizing-your-build-pipelines/"&gt;old article I wrote for comparison&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Culture: Have the Right People
&lt;/h2&gt;

&lt;p&gt;Culture is the weakest part of the whole book. It left me pretty cold. My theory is that BigTech has such a huge pool of candidates willing to join that it can rely on a pretty decent average for engineers. Some of the agile methodologies seem to make less sense in this context.&lt;/p&gt;

&lt;p&gt;Reading through these chapters didn’t feel too insightful. I’d rather check &lt;a href="https://hceris.com/book-review-team-topologies/"&gt;Team Topologies&lt;/a&gt;, &lt;a href="https://hceris.com/book-review-accelerate/"&gt;Accelerate&lt;/a&gt;, or plenty of other books.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;A few years ago, reading about Google practices could feel like science fiction. Nowadays, cloud providers and a host of SaaS tools for observability, feature toggles, and whatnot have made this tooling accessible. It doesn’t feel as foreign as it once did, although we’re still talking about a completely different game in terms of scale.&lt;/p&gt;

&lt;p&gt;Nevertheless, it’s an enjoyable read. You get a reasonable idea of how BigTech works internally, in case you &lt;a href="https://hceris.com/tips-for-coding-interviews-at-faang/"&gt;want to get in&lt;/a&gt;. The book gets ⭐⭐⭐⭐ stars from me.&lt;/p&gt;

</description>
      <category>bookreview</category>
      <category>softwareengineering</category>
      <category>practices</category>
      <category>testing</category>
    </item>
    <item>
      <title>My Approach to Taking Notes</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Mon, 11 Sep 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/my-approach-to-taking-notes-136o</link>
      <guid>https://dev.to/sirech/my-approach-to-taking-notes-136o</guid>
      <description>&lt;p&gt;Taking notes is kind of like flossing but for the corporate world. It’s essential yet frequently overlooked. We all know we should do it more, but we let other things get in the way.&lt;/p&gt;

&lt;p&gt;Good notes are helpful in &lt;em&gt;pretty much&lt;/em&gt; every possible situation. Let’s say you want &lt;a href="https://hceris.com/a-method-to-give-feedback/"&gt;to give feedback&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can wing it and hope you somehow remember what happened months ago. Or you can rely on your carefully collected notes and make your life way easier in the process. I know I prefer the second approach. Let me share how I go about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When To Take Notes
&lt;/h2&gt;

&lt;p&gt;I’m going to start with &lt;em&gt;when&lt;/em&gt; to take notes. I think the &lt;em&gt;cadence&lt;/em&gt; is the most important aspect of this whole endeavor. Yes, more important than &lt;em&gt;what&lt;/em&gt; you write or &lt;em&gt;where&lt;/em&gt; you maintain your notes. Consistency beats any fancy system you can think of.&lt;/p&gt;

&lt;p&gt;If it were so easy, though, everybody would be doing it already. The challenge lies in finding moments to take notes amidst a busy day. Over the years, I’ve figured out the specific times that work best for me. By using these opportunities to collect as many notes as possible, I’ll have an easier time once I sit down to think about the feedback I want to give.&lt;/p&gt;

&lt;h3&gt;
  
  
  During Meetings
&lt;/h3&gt;

&lt;p&gt;&lt;a href="///static/515148bb2a6db004b8b40ac64beb6fe1/c08c5/todo.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i0J7ZLHd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hceris.com/static/515148bb2a6db004b8b40ac64beb6fe1/c08c5/todo.jpg" alt="Todo" width="640" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;It never looks so clean in reality&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Meetings offer an excellent opportunity to observe how others present their ideas. It’s not just about the content. You can focus on what they ask, how they contribute, or how they explain their arguments. Small improvements in your communication increase your effectiveness in spreading your ideas. Thus, you can find plenty of suggestions to share with them.&lt;/p&gt;

&lt;p&gt;However, this isn’t easy to do! I struggle to take notes during meetings, more so if I’m actively participating. So, I limit myself to very short notes. Otherwise, I tend to get lost and miss the actual content of the meeting. That’s not what you want.&lt;/p&gt;
&lt;h3&gt;
  
  
  Shortly After the Meeting
&lt;/h3&gt;

&lt;p&gt;Taking notes straight after the meeting works better for me, while the information is fresh in my mind. It’s the perfect time to write it down and keep it for later.&lt;/p&gt;

&lt;p&gt;What if you have overlapping meetings without a break? I try to squeeze some quick note-taking during the short breaks in between them. It can make your day stressful as you sacrifice your breathing time. It’s not something to abuse. Even then, it’s so effective that it’s worth it for me.&lt;/p&gt;
&lt;h3&gt;
  
  
  At the End of the Week
&lt;/h3&gt;

&lt;p&gt;Before signing off for the weekend, I like to reflect on the week’s events. I check places like my calendar, open documents, or anywhere else where I can find the &lt;em&gt;stuff&lt;/em&gt; I was involved with for the past few days. I discover a lot of things to share that way, including some that seemed unimportant at the moment.&lt;/p&gt;

&lt;p&gt;It’s also a convenient time to balance between positive and critical points. I sometimes drift too much towards negativity, but I’ve found that having the weekend in front of me puts me in the mood to counteract it 😎.&lt;/p&gt;
&lt;h3&gt;
  
  
  At the End of the Month/Quarter
&lt;/h3&gt;

&lt;p&gt;This moment is the scaled-up version of the previous point. It’s also the one that many people are probably doing already, as it sort of aligns with retrospectives, quarter summaries, or similar. Still, it’s another good moment to look back and check if anything’s missing.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Take Notes
&lt;/h2&gt;

&lt;p&gt;Efficiency is &lt;em&gt;crucial&lt;/em&gt; when taking notes between other tasks. I optimize for speed and volume.&lt;/p&gt;

&lt;p&gt;I create separate notes for individual topics or people. I aim to write the shortest thing I can get away with, in chronological order and with timestamps. For future feedback, I keep context minimal. Instead, I limit myself to observed actions or behaviors. I may leave out the impact, as that’s something I can add later based on the facts.&lt;/p&gt;

&lt;p&gt;This note is quite raw and not meant for sharing. I leave enough of a trail to trace it back to the source. This is a lightly edited example from a previous gig:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;06.10

- update in the standup: what do you want to convey? what’s the level of details?
-- think of a structure: what happened, what’s coming up, what blocks

13.01

- lack of sync before the workshop, we had two conflicting messages

27.01

- kudos for fixing the CG dependency

23.02

- didn't leave an update before being off, was a bit confusing

05.04

- seemed like you were jumping straight into fixing the bug, without quantifying it first
-- could be taken as lack of prioritization
- what's next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes, I outsmart myself with some garbled notes so cryptic that I can’t decipher them afterward. That’s far from ideal. However, I can’t commit to writing tidy notes all the time. The occasional failure is an acceptable trade-off for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Logistics of Taking Notes
&lt;/h2&gt;

&lt;p&gt;I wouldn’t be too concerned about optimizing logistics as long as your system fits your workflow.&lt;/p&gt;

&lt;p&gt;Choosing between digital and handwritten notes is a personal preference. I prefer digital notes for easy access across devices, but sometimes, I resort to pen and paper for quick notes. Regardless of the format, ensure you can find your notes later. Otherwise, all the effort gets wasted.&lt;/p&gt;

&lt;p&gt;There are other points of view. For instance, this recent article from &lt;a href="https://www.allthingsdistributed.com/2023/06/a-few-words-on-taking-notes.html"&gt;Werner Vogels&lt;/a&gt; is full of praise for handwritten notes. If you want to be a CTO someday, maybe it’s worth copying that approach instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be Mindful of Where You Put Things
&lt;/h3&gt;

&lt;p&gt;&lt;a href="///static/123142fdbae31072bda23698787eb54e/c08c5/notebooks.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a8GG_cEQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hceris.com/static/123142fdbae31072bda23698787eb54e/c08c5/notebooks.jpg" alt="Notebooks" width="640" height="451"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Trying every software ever made&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It goes without saying, but you should only store notes where it’s allowed. I try very hard to avoid proprietary details in my notes. That stuff is better suited for official documents, wikis, or similar. Your notes can contain a reference that links to it.&lt;/p&gt;

&lt;p&gt;Feedback notes focus on behaviors. It’s relatively easy to write them in a way that you only talk about an individual’s actions and leave any unwanted internal detail. It’s worth getting used to writing things that are safe to share, in case you do it inadvertently.&lt;/p&gt;

&lt;p&gt;As for concrete software, there are a ton of solutions to choose from. I use Apple Notes for my personal stuff. I got notes about feedback I received or gave that go five or six years back there.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Make Notes Public
&lt;/h2&gt;

&lt;p&gt;As a general principle, you should consider making public anything that could help somebody else. This post, for instance, started as a direct response, but I thought it might benefit others 😊.&lt;/p&gt;

&lt;p&gt;Feedback isn’t the best example, as it’s something to share privately. For less personal topics, it’s good to ask yourself if somebody else would read it. Defaulting to sharing leverages what you already did. You can be more impactful with low extra effort. For instance, while migrating one service to the cloud, I had a lot of notes to understand AWS permissions in more detail. At some point, I realized I could show it to others, so I converted it into a &lt;a href="https://hceris.com/aws-iam-an-overview/"&gt;post about IAM&lt;/a&gt;. I shared it broadly and even reused it on different projects.&lt;/p&gt;

&lt;p&gt;You can see that it’s not completely true that making it public is for free. To publish a private note you need to edit it more heavily than when you’re the only consumer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes for Everything
&lt;/h2&gt;

&lt;p&gt;While I’ve focused on feedback throughout this article, it’s not the only thing that benefits from note-taking. The possibilities are endless, even something like &lt;a href="https://jvns.ca/"&gt;learning in public&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A long time ago, I read that John Carmack tracked his work in &lt;a href="https://garbagecollected.org/2017/10/24/the-carmack-plan/"&gt;.plan&lt;/a&gt; files. I liked the idea so much that I adopted it, although I keep mine private.&lt;/p&gt;

&lt;p&gt;Every now and then, I write down what I’ve been doing lately. I put a timestamp and document what happened. What I’m focusing on, what went well, anything that comes to mind. It’s insightful to go back and see my progress. It gives me perspective on how things are going without too much recency bias. That’s helped me a lot in tracking my growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Taking Notes
&lt;/h2&gt;

&lt;p&gt;The TLDR is that taking notes is inexpensive if you organize yourself. Moreover, it’s an extremely beneficial investment of your time. If you aren’t doing it now, you have to start. If you do, do it more often.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to Anna for the feedback.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>practices</category>
      <category>career</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A Method to Give Feedback</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Mon, 07 Aug 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/a-method-to-give-feedback-5ga5</link>
      <guid>https://dev.to/sirech/a-method-to-give-feedback-5ga5</guid>
      <description>&lt;p&gt;Feedback, when used thoughtfully, is a superpower. It accelerates personal growth faster than anything you can achieve through introspection alone.&lt;/p&gt;

&lt;p&gt;Over time, I’ve witnessed developers hinder their careers by repeatedly making the same fundamental mistake. Imagine influencing somebody’s trajectory by simply giving good feedback. That screams &lt;em&gt;Senior Engineer&lt;/em&gt; to me.&lt;/p&gt;

&lt;p&gt;Why is it, then, that so many people wait until the last day before the performance review submission deadline to finally write down something that’s way too superficial to be useful? I don’t know, man. Maybe it’s for lack of a method? In this article, I’m talking about my approach to delivering feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Constitutes Good Feedback?
&lt;/h2&gt;

&lt;p&gt;There are two aspects of giving feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;The content:&lt;/em&gt; The observation you’re attempting to share&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The delivery:&lt;/em&gt; How you share it with the intended recipient&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s begin with the content. You don’t need deep, career-changing insights to be helpful. More mundane observations are valuable and easier to come by. For instance, I tend to speak over others in meetings. While it might sound like a small thing to point out, receiving that feedback has helped me become more aware of it.&lt;/p&gt;

&lt;p&gt;Be sure to refer to &lt;strong&gt;concrete&lt;/strong&gt; events. Be as precise as possible to help the other person understand what you’re talking about. For the same reason, talk about &lt;strong&gt;recent&lt;/strong&gt; events. Memory gets hazy over time. It’s significantly easier to discuss something when it’s fresh on your mind. At the same time, it’s probably good to avoid giving feedback &lt;em&gt;immediately&lt;/em&gt; after the fact. Waiting a bit helps cool down.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/b38a3efa4d78f577f78038f79c216ee8/eea4a/deer.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KVx09Rlm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hceris.com/static/b38a3efa4d78f577f78038f79c216ee8/acb04/deer.jpg" alt="deer" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;actionable insights&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, your input should be &lt;strong&gt;actionable&lt;/strong&gt;. What’s there to do differently next time? A situation with no realistic alternative is a dead end. Feedback is about finding ways to improve yourself, not grading your performance.&lt;/p&gt;

&lt;p&gt;Lastly, it should be &lt;strong&gt;constructive&lt;/strong&gt;. &lt;em&gt;You suck&lt;/em&gt; isn’t feedback, even if you phrase it nicely. If you can’t find a way to frame it so that it helps the person grow, it’s probably better to let it go.&lt;/p&gt;

&lt;p&gt;As an example of what &lt;em&gt;not&lt;/em&gt; to do, I remember a manager in a previous company telling me something akin to &lt;em&gt;Why do you repeat yourself so much?&lt;/em&gt;, in a way that sounded more like an accusation than a question. I actually went and asked a few colleagues if they had observed this, as I was taken aback. That feedback didn’t land well at all.&lt;/p&gt;

&lt;p&gt;In summary, keep the following in mind when preparing the content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It should be &lt;strong&gt;recent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It should be &lt;strong&gt;concrete&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It should be &lt;strong&gt;actionable&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It should be &lt;strong&gt;constructive&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Situation-Behavior-Impact
&lt;/h2&gt;

&lt;p&gt;Let’s say you have the content ready. The next step is figuring out the &lt;em&gt;delivery&lt;/em&gt;. Giving feedback can be difficult, especially if it’s not positive. That’s why I like to stick to a structured pattern commonly referred to as &lt;strong&gt;Situation-Behavior-Impact&lt;/strong&gt;. You have three distinct phases:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Situation&lt;/em&gt; describes the context, so that the receiver knows what you’re talking about. This ties back to using a concrete example. Moreover, it being a recent situation means both of you are more likely to remember the details, avoiding misunderstandings. Your goal should be to set up the stage, not to bore the other person. After all, they were there as well. Make it as short as you can.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Behavior&lt;/em&gt; is about describing the actions you observed. &lt;strong&gt;Key&lt;/strong&gt; word being observed. Acting as if you know exactly what somebody else was thinking is condescending and counterproductive. You’ll probably be wrong, and it won’t land very well.&lt;/p&gt;

&lt;p&gt;Instead of reading minds, focus on your observations. Make it clear that this is your perspective, which might be incomplete or even incorrect. Use a neutral tone and avoid making judgments. Your goal is to talk about actions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Impact&lt;/em&gt; is the last part of the puzzle. What did the previous behavior &lt;em&gt;cause&lt;/em&gt;, on you or somebody else? Talking about impact can be uncomfortable, but it’s a necessary part of a complete piece of feedback. Based on this impact, the receiver can reflect and decide to do things differently the next time.&lt;/p&gt;

&lt;p&gt;Similarly to the behavior part, focus on what you saw. Using a fixed structure can feel forced, but it ensures consistency. When you’re raising a thorny issue, this formula helps you concentrate on being as objective as possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/ca0e5798128350e9c518972780b90eee/eea4a/impact.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tgOJOMSR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hceris.com/static/ca0e5798128350e9c518972780b90eee/acb04/impact.jpg" alt="impact" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Landing some impact&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another example: I used to work in consulting. In my first project, we developed some CI/CD infrastructure for a traditional German company. I was a bit overwhelmed as I wasn’t familiar with the tooling. A senior colleague gave me some harsh feedback about me being hesitant to make decisions, which was diminishing my credibility with the client. It wasn’t easy to hear, I can tell you that much.&lt;/p&gt;

&lt;p&gt;However, my colleague was structured in how he delivered the feedback. He was concrete about the meeting he was referring to. He described the actions he was seeing from me. Lastly, while he was clear about the impact it was having, he wasn’t judgemental. On the contrary, he was keen to support me. The structure made this tough message more digestible. Building a plan to address the issues felt a lot easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice!
&lt;/h2&gt;

&lt;p&gt;Sharing imperfect feedback is preferable to sharing nothing, as long as you remain respectful and constructive. Remember that any formula isn’t a substitute for practice. The only way to get better is to do it regularly. Don’t leave it for the last possible moment. Take notes and share them regularly, and it’ll progressively get easier over time.&lt;/p&gt;

&lt;p&gt;I prefer giving feedback in person. I always thought that what you write for an official review shouldn’t surprise the receiver. However, if you feel more comfortable over chat or email, use that medium. Remove the barriers that are preventing you from doing it more often.&lt;/p&gt;

&lt;p&gt;Another option is to go to the person’s manager directly and share the feedback with them. Honestly, that sounds very foreign to me, so I have a hard time picturing myself doing it. I believe that building trust with others to a point where you can freely share and receive feedback is a better long-term investment for yourself. But, hey, I guess that &lt;em&gt;some&lt;/em&gt; feedback is better than just eschewing the practice altogether.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beware of Rigid Formulas
&lt;/h2&gt;

&lt;p&gt;Even though a structured method like &lt;strong&gt;SBI&lt;/strong&gt; can help, you should be ready to abandon any method and be adaptable instead. Feedback is a very personal thing. People have different preferences regarding format, medium, or anything else. Adapting your delivery to accommodate these preferences will improve effectiveness. Especially so for people with whom you collaborate more closely and have more to share.&lt;/p&gt;

&lt;p&gt;For instance, some resources recommend using the &lt;em&gt;feedback sandwich&lt;/em&gt;, where you wrap a negative piece of feedback in between two good ones. I despise this method and find it fake and artificial. It just doesn’t work for me. Everybody has their anti-patterns, so it’s a good idea to figure out those over time.&lt;/p&gt;

&lt;p&gt;Using a formula allows you to be consistent. However, it’s more important to be &lt;em&gt;genuine&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s Not Up to You Anymore
&lt;/h2&gt;

&lt;p&gt;Alright, so your carefully crafted feedback is ready, and you go out and share it with the intended recipient. What’s next?&lt;/p&gt;

&lt;p&gt;Not much, really. In my opinion, you did your job already. Now, it’s up to that person to digest it, reflect upon it, and decide how to act on it. It might well be that they choose to discard it. That’s not necessarily bad! Remember that you only have a limited view of how somebody else acts and behaves.&lt;/p&gt;

</description>
      <category>practices</category>
      <category>career</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Book Review: Unit Testing</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Tue, 18 Apr 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/book-review-unit-testing-1fke</link>
      <guid>https://dev.to/sirech/book-review-unit-testing-1fke</guid>
      <description>&lt;p&gt;&lt;a href="///static/2fc83852bd94306d390402bf2d950a7f/f21e7/cover.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ttXT391V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hceris.com/static/2fc83852bd94306d390402bf2d950a7f/f21e7/cover.png" alt="Unit Testing" width="360" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.manning.com/books/unit-testing"&gt;Unit Testing&lt;/a&gt; is a book that, despite its title, isn’t just about unit testing. While that’s a significant portion of the book, there’s more.&lt;/p&gt;

&lt;p&gt;You get a lot of advice on how to write tests. How to make them effective and leverage those tests to improve code through refactorings. It touches on other topics, such as mocks or even integration tests. There’s a lot of good stuff to mention in just a few lines.&lt;/p&gt;

&lt;p&gt;Anyhow, two parts stood out the most to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pillars of a Good Test
&lt;/h2&gt;

&lt;p&gt;How do you recognize a good test? As a big proponent of testing, I’ve thought a lot about that through the years. &lt;em&gt;It should be worth the effort&lt;/em&gt; has been my intuition for a long time.&lt;/p&gt;

&lt;p&gt;The author has more concrete ideas. He provides four pillars for a good unit test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protection against regressions&lt;/li&gt;
&lt;li&gt;Resistance to refactoring&lt;/li&gt;
&lt;li&gt;Fast feedback&lt;/li&gt;
&lt;li&gt;Maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They all make sense to me and don’t merit an extended explanation. More interesting is the relationship between them. The first three are related to each other. Resistance to refactoring is rather binary. A test is either resistant to refactoring or it isn’t. Thus, it comes down to balancing between protection against regressions and fast feedback. Coincidentally, that’s the continuum between end-to-end tests and unit tests.&lt;/p&gt;

&lt;p&gt;I recommend reading this chapter carefully, as it’s a novel idea that I hadn’t seen before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Deploy Tests Effectively
&lt;/h2&gt;

&lt;p&gt;What types of code are there? The book lists four types: Domain model/Algorithms, trivial code, overcomplicated code, and controllers. They’re all pretty self-descriptive. And they all have well-defined actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Trivial code&lt;/em&gt; isn’t worth testing&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The domain model&lt;/em&gt; is covered with unit tests&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Controllers&lt;/em&gt; are covered with integration tests&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Overcomplicated code&lt;/em&gt; shall be refactored by splitting it into domain model and controllers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It makes a lot of sense! Testing is all about return on investment. You have limited resources and have to deploy them wisely. And it turns out, there’s code that’s &lt;em&gt;too easy&lt;/em&gt; to test, and there’s code that’s &lt;em&gt;too hard&lt;/em&gt; to test. I like the idea of accepting that neither is the target.&lt;/p&gt;

&lt;p&gt;A common complaint against testing stems, I believe, from treating all code equally instead of following a guideline like this to maximize impact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;Testing is a fundamental part of software engineering. Thankfully, that’s fairly accepted throughout the industry today. However, there’s a lot of variance in the effectiveness of testing efforts.&lt;/p&gt;

&lt;p&gt;If you want to increase your testing skills, which you should, this book is one of the best resources I know. It packs a remarkable amount of highly actionable information in fewer than 300 pages. It’s concrete enough to be broadly applicable in many situations. I found it one of the most useful books I’ve read in a while, and I plan to re-read it more than once. It gets ⭐⭐⭐⭐⭐ stars from me.&lt;/p&gt;

</description>
      <category>bookreview</category>
      <category>softwareengineering</category>
      <category>practices</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Humble Extract Method</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Mon, 27 Feb 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/the-humble-extract-method-103g</link>
      <guid>https://dev.to/sirech/the-humble-extract-method-103g</guid>
      <description>&lt;p&gt;After reviewing a lot of code in the past couple of months, I’ve realized that I regularly leave comments like this one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we break this down into smaller pieces?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="/static/50ecbbe08d280c18e51685dc01032100/bfe25/cover.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhceris.com%2Fstatic%2F50ecbbe08d280c18e51685dc01032100%2Facb04%2Fcover.jpg" title="Refactoring" alt="Refactoring" width="750" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Turns out, I like to advocate for shorter methods. Is this the right thing to pay attention to? I think so. I strongly believe that breaking down code is often the most cost-effective way to increase maintainability.&lt;/p&gt;

&lt;p&gt;For that, the best alternative is &lt;em&gt;extracting smaller methods&lt;/em&gt;. It’s easy and works consistently. It should be part of every developer’s toolkit.&lt;/p&gt;

&lt;p&gt;In this article, I’m writing about the simple yet powerful extract method refactoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Extract Method, Exactly?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Extract method&lt;/em&gt; is &lt;a href="https://refactoring.com/catalog/extractFunction.html" rel="noopener noreferrer"&gt;a refactoring&lt;/a&gt; where you move a code fragment to a separate function with a name that describes its purpose. Consider this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;splitNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;split&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="c1"&gt;// convert each string to a number&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;numbers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toInt&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;numbers&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example is too small to truly benefit from breaking it down, so bear with me for the sake of the example. Anyway, there’s a section that converts a string to a number. It’s a prime candidate for extraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;splitNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;split&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;numbers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;convertStringToNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;split&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;numbers&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;convertStringToNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&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;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;()&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 it is! We now have a proper submethod instead of an inline comment. For a more realistic scenario, imagine this was a hundred lines long instead of five. The good thing is, the approach would work the exact same way. Moreover, you can repeat the procedure and break down the new methods.&lt;/p&gt;

&lt;p&gt;All in all, this refactoring is pretty straightforward. In fact, it’s been supported by IDEs like &lt;a href="https://www.jetbrains.com/help/idea/extract-method.html" rel="noopener noreferrer"&gt;IntelliJ&lt;/a&gt; for basically forever. And yet! Despite its simplicity, this humble change brings quite a lot of value. Let’s talk about its benefits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shorter Methods Improve Readability
&lt;/h2&gt;

&lt;p&gt;The most obvious outcome of using &lt;em&gt;Extract Method&lt;/em&gt; is that it makes methods &lt;strong&gt;short&lt;/strong&gt;. Is that a good thing, though?&lt;/p&gt;

&lt;p&gt;Yes! Let me argue why. Shortening methods is necessary to get them to do one thing only (also known as the &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle" rel="noopener noreferrer"&gt;Single Responsibility Principle&lt;/a&gt;). Methods that do one thing are generally less complex. They require less knowledge about the surrounding context.&lt;/p&gt;

&lt;p&gt;When you navigate a big codebase, you can’t keep every detail in your head. If you have short, single-purpose methods you can tune out some complexity and focus on one part at a time. That, in my mind, leads to a massive readability boost.&lt;/p&gt;

&lt;p&gt;One argument I’ve heard against extracting methods is that it’s easier to understand code if it’s all in the same place. I find the reasoning unsatisfying. In my opinion, it assumes you’ll be able to zoom in and focus on the relevant parts as you read through a possibly massive block. To do that, you need to be pretty familiar with the codebase already. Otherwise, you’re going to struggle.&lt;/p&gt;

&lt;p&gt;In my view, a more sustainable alternative is to rely on abstract methods that hide implementation details. That way, even if your understanding is incomplete you’ll still be effective. Note that this only holds true if the abstractions are &lt;em&gt;good&lt;/em&gt;. If the division doesn’t make any sense, you’ll be without a doubt worse off.&lt;/p&gt;

&lt;p&gt;How short is short enough? That’s a matter of debate and preference. Hear &lt;a href="https://www.oreilly.com/library/view/clean-code-a/9780136083238/" rel="noopener noreferrer"&gt;Uncle Bob&lt;/a&gt; for some guidance:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My rule is “extract till you drop”. A function is too big if I can meaningfully extract another function from it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Extracting Methods is an Opportunity for Good Naming
&lt;/h2&gt;

&lt;p&gt;Naming is hard. And yet, without good names extracting methods isn’t worth it. Even if the abstraction is good, a bad name makes it inaccessible. Thus, good naming is crucial for readability.&lt;/p&gt;

&lt;p&gt;A name that describes the method’s purpose serves as lightweight documentation. Documentation that’s supported by the language, unlike comments. Automated tooling can find and change methods in a way that’s usually impossible in ad-hoc comments.&lt;/p&gt;

&lt;p&gt;If you’re struggling to find a name for an extracted method, it can be a sign of two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An unclear boundary, and thus a fuzzy responsibility. That makes it hard to find a proper name&lt;/li&gt;
&lt;li&gt;The method is still too big and needs to be split further&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Not Bad, and There Is More
&lt;/h2&gt;

&lt;p&gt;The combination of smaller methods and better names reduces cognitive load. Each method serves as a small reusable abstraction. For instance, something as typical as iterating over a list to apply a function to every element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&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;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better alternative is to use a higher-level abstraction, in this case, &lt;code&gt;map&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;it&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;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;map&lt;/code&gt; encapsulates the implementation and lets you focus on what you want to express.&lt;/p&gt;

&lt;p&gt;Anyhow. While shorter methods and better names are the big two aspects, other considerations that speak for using this refactoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nesting Is Another form of Complexity
&lt;/h3&gt;

&lt;p&gt;Excessive length isn’t the only way complexity creeps in. Code that’s nested multiple layers deep is as hard to read as an overly long piece of code. It can hide bugs as you inadvertently put things in the wrong scope.&lt;/p&gt;

&lt;p&gt;Luckily, extracting methods reduces nesting the same way that it reduces length.&lt;/p&gt;

&lt;h3&gt;
  
  
  Small Methods Reduce Coupling
&lt;/h3&gt;

&lt;p&gt;Dependencies make it harder to reason about code. They make it harder to change as well.&lt;/p&gt;

&lt;p&gt;Suppose you have a massive method. There are plenty of local variables capturing intermediate results. While they provide an opportunity for meaningful names, they lack the encapsulation that methods provide. You have access to everything that happened before within the same scope, which can entangle the logic beyond salvation.&lt;/p&gt;

&lt;p&gt;Not only that, you start getting worried about unexpected changes. You can’t be sure that the variable wasn’t modified unless you painstakingly go through the whole logic. Doubly so in languages that don’t allow read-only variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  What About Testability?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="/static/2b283964c3da3e9d74ce30511601be03/2afb1/working-effectively.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhceris.com%2Fstatic%2F2b283964c3da3e9d74ce30511601be03%2F2afb1%2Fworking-effectively.jpg" title="Working Effectively with Legacy Code" alt="Working Effectively with Legacy Code" width="284" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And lastly, we come to testability. Does extracting methods improve testability? You could argue it doesn’t, as you should have your tests ready &lt;em&gt;before&lt;/em&gt; you perform the refactoring.&lt;/p&gt;

&lt;p&gt;However! Reality isn’t always so kind. You might face a huge, gnarly class that lacks tests. Writing tests might prove impossible unless you make the problem more manageable.&lt;/p&gt;

&lt;p&gt;As described in the book &lt;a href="//../book-review-working-effectively-with-legacy-code/"&gt;Working Effectively with Legacy Code&lt;/a&gt;, extracting methods allows you to break down smaller pieces. At some point, they become small enough that you can write some tests for them.&lt;/p&gt;

&lt;p&gt;It’s not pretty, but it gets the job done. Much better than the alternative of not really knowing if your changes will screw something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notice I Didn’t Talk about Reuse
&lt;/h2&gt;

&lt;p&gt;I haven’t mentioned reusability throughout the article. It is, in fact, not the primary goal of &lt;em&gt;Extract Method&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A smaller auxiliary method is valuable even if we only use it once. Making code more readable is already a significant benefit, worth doing on its own. If that method encapsulates a reusable abstraction, that’s a welcome benefit. But it’s not something to force or expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Extracting Methods Worth The Effort?
&lt;/h2&gt;

&lt;p&gt;In any big codebase, the code developers write lives for a long time. Often, it’s still there while the original developers moved somewhere else. Meanwhile, new developers will read it many times and try to figure out what it does. Capturing the context of why a decision happened is hard, so these poor developers are left without context.&lt;/p&gt;

&lt;p&gt;Thus, it will be read many times by multiple developers. Investing some effort in making it more readable pays off more and more over time.&lt;/p&gt;

&lt;p&gt;Not that you should overdo it, though. An endless collection of one-liners isn’t an improvement, either. Aim for methods that stand on their own and have one purpose. That’s a reasonable guideline to follow.&lt;/p&gt;

</description>
      <category>practices</category>
      <category>softwareengineering</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>Book Review: Effective Remote Work</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Sun, 27 Nov 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/book-review-effective-remote-work-5a94</link>
      <guid>https://dev.to/sirech/book-review-effective-remote-work-5a94</guid>
      <description>&lt;p&gt;&lt;a href="/static/969c0e90551a1c7cb3717ecffe93d726/066f9/cover.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhceris.com%2Fstatic%2F969c0e90551a1c7cb3717ecffe93d726%2F066f9%2Fcover.jpg" title="Effective Remote Work" alt="Effective Remote Work" width="400" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pragprog.com/titles/jsrw/effective-remote-work/" rel="noopener noreferrer"&gt;Effective Remote Work&lt;/a&gt; is a book about, well, remote work. The author, James Stanier, works for &lt;a href="https://shopify.engineering/" rel="noopener noreferrer"&gt;Shopify&lt;/a&gt;, a company with a long tradition of working remotely.&lt;/p&gt;

&lt;p&gt;These past few years have been a large-scale experiment in working remotely for most tech companies. However, the way it happened was so abrupt and unprepared that many people had a miserable experience.&lt;/p&gt;

&lt;p&gt;It’s time to correct that! Despite the bumpy start, many companies still offer at least hybrid work. It seems this practice is here to stay. This book is a great resource about making remote work effective, productive, and sustainable. Let’s go over some of the things it mentions.&lt;/p&gt;

&lt;h2&gt;
  
  
  No Second-class Citizens
&lt;/h2&gt;

&lt;p&gt;The book advocates treating everybody as a remote worker. I like that goal. You start with basic stuff like ensuring you don’t forget to include remote people in meetings. But it goes beyond that. Are they included in decision-making? Do they have the same career opportunities as people going to the office daily?&lt;/p&gt;

&lt;h2&gt;
  
  
  Proper Onboarding
&lt;/h2&gt;

&lt;p&gt;A good onboarding plan is a must whether you work remotely or not. Working remotely magnifies a bad experience. Sitting at home feeling helpless because you don’t know something is frustrating. Remote workers need to be able to unblock themselves, and you need to help them with that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Durable Artifacts
&lt;/h2&gt;

&lt;p&gt;This point completely matches my experience in the past three years of working remotely almost full-time. Collaboration around &lt;strong&gt;durable&lt;/strong&gt; artifacts should be at the center of everything you do. If you don’t regularly create easily accessible documents, you’ll repeat the same conversations over and over. Or, even worse, decisions will happen ad-hoc in secret meetings.&lt;/p&gt;

&lt;p&gt;Good technical writing makes written communication better. Go check &lt;a href="https://developers.google.com/tech-writing/overview" rel="noopener noreferrer"&gt;Google’s courses&lt;/a&gt; for a great resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spectrum of Synchronousness
&lt;/h2&gt;

&lt;p&gt;People might not answer immediately when you have a question. You need to balance between things that require synchronous communication and the ones that can wait. If you have worked with people in different time zones you’ll know what I mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Remote Test
&lt;/h2&gt;

&lt;p&gt;Similar to &lt;a href="https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/" rel="noopener noreferrer"&gt;the Joel Test&lt;/a&gt;, the book ends with a list of criteria for remote work. The questions that help determine if you’re ready are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do you treat everyone as remote?&lt;/li&gt;
&lt;li&gt;Do you provide a remote workspace setup?&lt;/li&gt;
&lt;li&gt;Do you spend money equally on in-office and remote staff?&lt;/li&gt;
&lt;li&gt;Do you optimize for asynchronous communication?&lt;/li&gt;
&lt;li&gt;Do you create artifacts from synchronous interactions?&lt;/li&gt;
&lt;li&gt;Do you measure staff by their impact?&lt;/li&gt;
&lt;li&gt;Do you allow staff to choose flexible hours?&lt;/li&gt;
&lt;li&gt;Are the members of the executive team remote workers?&lt;/li&gt;
&lt;li&gt;Do you use the best collaborative tools that money can buy?&lt;/li&gt;
&lt;li&gt;Do you hire staff anywhere in the world?&lt;/li&gt;
&lt;li&gt;Do you support families as well as employees?&lt;/li&gt;
&lt;li&gt;Do you give back to an employee’s local community?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;This book is very poignant now that remote work has normalized to a never-seen-before degree. Many companies have embraced the practice. Thus, it’s worth investing in understanding how to be effective in this environment. Compared to another book like &lt;a href="https://www.amazon.com/Remote-Office-Required-Jason-Fried/dp/0804137501" rel="noopener noreferrer"&gt;Remote: Office Not Required&lt;/a&gt;, there’s a lot of actionable advice that you can apply starting today. It gets ⭐⭐⭐⭐ stars from me.&lt;/p&gt;

</description>
      <category>bookreview</category>
      <category>softwareengineering</category>
      <category>practices</category>
      <category>teamorganization</category>
    </item>
    <item>
      <title>Anatomy of a Successful Retro</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Sun, 16 Oct 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/anatomy-of-a-successful-retro-4gbe</link>
      <guid>https://dev.to/sirech/anatomy-of-a-successful-retro-4gbe</guid>
      <description>&lt;p&gt;Retrospectives are an integral part of &lt;a href="https://www.atlassian.com/agile"&gt;Agile&lt;/a&gt;. When they are effective, they provide a powerful tool for continuous improvement. However, when they go wrong they become a catalyst for frustration and pointless venting. You don’t want to end your week on such a negative note, do you?&lt;/p&gt;

&lt;p&gt;While I won’t claim to be an expert facilitator, I’ve experienced my fair share of crappy retros to know what I like and don’t like. Let’s talk about how to run retros productively. You don’t need a dedicated agile coach to get meaningful outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Retro?
&lt;/h2&gt;

&lt;p&gt;Short and sweet: It’s a regular meeting where the team comes together and reflects on all that has happened lately. You discuss the most promising topics and seek actions to improve.&lt;/p&gt;

&lt;p&gt;How do you recognize a good retro? Well, what about the opposite question? What are some retro smells that can doom the whole endeavor?&lt;/p&gt;

&lt;h2&gt;
  
  
  Retro Smells
&lt;/h2&gt;

&lt;p&gt;&lt;a href="///static/3f2ea0eda73278e99fa60838885f6d0e/e4c4d/debate.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z1ZeUXJ0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/3f2ea0eda73278e99fa60838885f6d0e/acb04/debate.jpg" alt="Debate" title="Debate" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Healthy debate&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The one thing that grinds my gears is poor time management. For example, collecting stickies for 55 minutes and then realizing that you have only five minutes to half-ass some action items.&lt;/p&gt;

&lt;p&gt;Another questionable habit is talking about things that you can’t influence. Don’t get me wrong: sometimes it’s good to vent and blow off steam. But it can’t become the norm. Otherwise, you’ll create a fountain of negativity.&lt;/p&gt;

&lt;p&gt;My last personal favorite is the topic that comes up repeatedly, without ever getting to any resolution. Extra points if it’s an overly generic thing like &lt;em&gt;not enough communication&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Everybody has their pet peeves. As a facilitator, it’s your job to sidestep them and foster a productive ritual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following A Structure
&lt;/h2&gt;

&lt;p&gt;I tend to follow a familiar structure. I want &lt;em&gt;repeatability&lt;/em&gt; and &lt;em&gt;predictability&lt;/em&gt;. That’s easier to do with a general framework. At the same time, you want to adapt to what people want to talk about. This is my rough script for a 60 minutes slot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set the Tone&lt;/li&gt;
&lt;li&gt;Icebreaker&lt;/li&gt;
&lt;li&gt;Previous Actions&lt;/li&gt;
&lt;li&gt;Reflection&lt;/li&gt;
&lt;li&gt;Actions&lt;/li&gt;
&lt;li&gt;Wrap-Up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go a bit more into detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set the Tone
&lt;/h3&gt;

&lt;p&gt;Start with a quick (I repeat, quick) reminder that a retrospective is a safe space. Have you read the &lt;a href="http://retrospectivewiki.org/index.php?title=The_Prime_Directive"&gt;Prime directive&lt;/a&gt;? It does sound a bit tacky, to be fair. Behind the “Star Trek”-like message hides an important question: Are people comfortable talking about potentially uncomfortable topics? If not, you have serious problems that can’t be fixed by gathering people in a room. Sorry for that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Icebreaker
&lt;/h3&gt;

&lt;p&gt;Icebreakers are small activities to lighten the mood. It seems silly, but it doesn’t hurt, provided you don’t invest too much time. Focus on the positive.&lt;/p&gt;

&lt;p&gt;The icebreaker that consistently works best for me is collecting kudos. Spend a few minutes letting people thank others for their work and contributions. Share it broadly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Previous Actions
&lt;/h3&gt;

&lt;p&gt;It’s crucial to keep track of the actions decided in previous retrospectives. Are you accumulating a long list of unclaimed actions that won’t ever happen? That’s a huge red flag.&lt;/p&gt;

&lt;p&gt;I like to go over previous actions to check progress. For the incomplete ones, it’s worth ensuring they’re still relevant and necessary. Prune the obsolete ones, and carry the rest as part of this iteration. It’s fine, but keep an eye on actions that never go anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reflection
&lt;/h3&gt;

&lt;p&gt;Now comes the meaty part. You’re going to do an exercise where you leave time for the participants to collect their thoughts and write them down in stickies. There are many formats for this. A typical one is to use three buckets like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start Doing&lt;/li&gt;
&lt;li&gt;Stop Doing&lt;/li&gt;
&lt;li&gt;Continue Doing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Areas that aren’t going well hold the most potential for improvement. Nevertheless, don’t tunnel too much on those. A reminder of activities worth keeping alive can be very useful, even if it doesn’t merit further debate.&lt;/p&gt;

&lt;p&gt;Be very, very careful of sticky overdose. Collecting 50 stickies is great until you realize you won’t get to discuss 95% of them. Here is the spot where many retros go awry. Limit the number of stickies to keep the logistics manageable.&lt;/p&gt;

&lt;p&gt;Once you collect all these wonderful ideas it’s time to read them to ensure they’re clear to everybody. Then, group them and let people vote for the ones they want to discuss. This is a clarification process, don’t allow discussions to start just yet. Some people love to talk about their pet issues regardless of priority. They might monopolize the limited time if you aren’t careful.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/a09dc4bd544cc4197ceca2865fda1aa8/1a77e/timer.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZfZJv5rM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/a09dc4bd544cc4197ceca2865fda1aa8/acb04/timer.jpg" alt="Timer" title="Timer" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The most important tool in any retro&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;No matter how efficient you are, you’ll have consumed about half the time by now. You’ll have time for about three topics. I like to use a very rigid structure for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick the most-voted topic&lt;/li&gt;
&lt;li&gt;Start a timer for 7 minutes. Use the slot to explore the problem and think of actions&lt;/li&gt;
&lt;li&gt;Once the timer is over, I move on to the next topic. If I feel that people still want to talk a bit more, I do a quick thumbs up / thumbs down vote to confirm the suspicion. You might discuss fewer topics, but you don’t leave a conversation unfinished&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might read this and recoil in horror. It’s so formulaic! However, there’s a reason behind it. If you want to finish on time, you’ll have to be ruthless with time management. If you explain the rules in advance, it feels less rude and awkward. Remember, we’re committed to finishing on time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="///static/917e53d161dead098389206d79c3360a/2334a/action.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gbcf_Rfx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/917e53d161dead098389206d79c3360a/2334a/action.jpg" alt="Action" title="Action" width="169" height="300"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Realistic actions&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A healthy discussion has value on its own, but we want to foster improvement. That requires some actions. As the facilitator, you have to be on the lookout for them. Pounce when given the opportunity.&lt;/p&gt;

&lt;p&gt;There are plenty of catchy acronyms to define good action items, such as &lt;a href="https://en.wikipedia.org/wiki/SMART_criteria"&gt;SMART&lt;/a&gt;. Follow the one you like. Remember that any action needs to be doable in a reasonable time frame. Ideally before the next retro. I refuse to write down commitments unless I can assign a person to them. I think that actions without an owner are as good as useless.&lt;/p&gt;

&lt;p&gt;What if you don’t find any actions to take? It’s not ideal, but it happens. I’ve seen facilitators push to get some action, any action will do. I disagree with this approach. If you couldn’t find a meaningful thing to do, so be it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap-Up
&lt;/h3&gt;

&lt;p&gt;If you did everything well until now, you’ll have about one minute left to wrap up, summarize the actions, and thank everybody for their time. Well done, recruit!&lt;/p&gt;

&lt;p&gt;Write this summary down somewhere, especially the actions. Make sure that you aren’t sharing things you shouldn’t.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling it Up
&lt;/h2&gt;

&lt;p&gt;So we got one decent retro. Good! Now let’s make it a regular occurrence. There’s no reason that you can’t get a reproducible result.&lt;/p&gt;

&lt;p&gt;I believe that team rituals shouldn’t be owned by an individual. Spreading them across the team increases ownership. Thus, I think moderation should rotate among the people on the team. It’s good practice for them and an antidote against having the same people talking all the time.&lt;/p&gt;

&lt;p&gt;As a parting piece of advice, shake things up! Repeating the same format all the time puts people on auto-pilot. Switch formats occasionally to keep it fresh. Every now and then, do a completely different thing. A futurospective about where the team wants to be next year. Focus on only one topic that’s important for the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Do We Actually Get Out of Retrospectives?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="///static/90e31e51b5846db33dc9632b4869fcda/b2234/zen.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3gjDSdbW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/90e31e51b5846db33dc9632b4869fcda/acb04/zen.jpg" alt="Zen" title="Zen" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Enlightment state&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Getting quality action items is good. Implementing them within a reasonable time frame is even better. Let’s start with that.&lt;/p&gt;

&lt;p&gt;That said, I think retrospectives are also about creating a culture of reflection. It’s easy to let routine take over and do things the same way as before. Reflective teams are proactive in finding ways of improving on their own. A good retrospective is one small step towards that lofty goal.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>practices</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>The Behavioral Interview</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Wed, 07 Sep 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/the-behavioral-interview-4o7f</link>
      <guid>https://dev.to/sirech/the-behavioral-interview-4o7f</guid>
      <description>&lt;p&gt;The behavioral interview is the last component of the interview loop at &lt;a href="https://en.wikipedia.org/wiki/Big_Tech"&gt;BigTech&lt;/a&gt;. It’s not, as its name implies, a technical interview. Instead, it focuses on your previous experience. You’re there to show that you understand how to act and communicate. It’s similar to the System Design round in that it weighs more heavily for senior candidates.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Well, I don’t need preparation to talk about my experience&lt;/em&gt;, you might think. And you’d be wrong. Don’t underestimate this interview or you will fail it miserably. A behavioral interview isn’t an informal chat where you reminisce about your previous experience and have a good laugh in the end. There are clear expectations.&lt;/p&gt;

&lt;p&gt;I’m ending my series about interviewing talking about this interview format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure of a Behavioral Interview
&lt;/h2&gt;

&lt;p&gt;A behavioral interview centers around open-ended questions. There are many, many &lt;a href="https://igotanoffer.com/blogs/tech/amazon-behavioral-interview"&gt;sample questions&lt;/a&gt; on the internet. They tend to sound similar, though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tell me about a project where you had a big impact&lt;/li&gt;
&lt;li&gt;Tell me how you solved a conflict between multiple teams&lt;/li&gt;
&lt;li&gt;Tell me about a time when you had to make a quick decision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that these questions focus on your &lt;em&gt;previous&lt;/em&gt; experience, not hypothetical scenarios. The reasoning is that it’s easier to understand how you think by hearing about what you did already.&lt;/p&gt;

&lt;p&gt;These questions are vague and undefined. However, that doesn’t mean you should answer with the first thing that comes to mind. Doing so is a recipe for rejection. Instead, the canonical advice is to use the &lt;a href="https://interviewsteps.com/blogs/news/amazon-star-method"&gt;STAR&lt;/a&gt; method. While that’s the right starting point, we can build on top and do better. Allow me to explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  STAR is Flawed
&lt;/h2&gt;

&lt;p&gt;&lt;a href="///static/75312e3aa45b27bcfecdb798c293491b/c42e5/book.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hw3MCdNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/75312e3aa45b27bcfecdb798c293491b/acb04/book.jpg" alt="Book" title="Book" width="750" height="497"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;This response could be shorter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;STAR (&lt;em&gt;Situation&lt;/em&gt;, &lt;em&gt;Task&lt;/em&gt;, &lt;em&gt;Action&lt;/em&gt;, &lt;em&gt;Result&lt;/em&gt;) is a way of structuring your answers to any behavioral question. You start explaining the context. Then, you talk about your task. You follow with your actions, and in the end, you round it up with the results of those actions. Using this structure ensures that you tell a coherent story.&lt;/p&gt;

&lt;p&gt;There’s a problem, and it has to do with repetition. In practice, &lt;em&gt;Situation&lt;/em&gt; and &lt;em&gt;Task&lt;/em&gt; often overlap significantly. If you follow the method rigidly you’ll end up mostly saying the same thing twice. It might sound innocuous, but you can’t afford to use your limited time inefficiently.&lt;/p&gt;

&lt;p&gt;In these interviews, time is your enemy. At Meta, for instance, they last 45 minutes. That includes the introduction and &lt;em&gt;your&lt;/em&gt; questions, mind you. You won’t have enough time to talk about all the wonderful things you have done. Repeating yourself leaves you less time to provide useful signal. It makes the interviewer’s evaluation harder, which reduces your chances.&lt;/p&gt;

&lt;p&gt;I prefer using a streamlined version of STAR. Let’s call it PAR: &lt;em&gt;Problem&lt;/em&gt;, &lt;em&gt;Action&lt;/em&gt;, &lt;em&gt;Result&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using PAR
&lt;/h2&gt;

&lt;p&gt;Let’s say you get one of the aforementioned questions. You come prepared and want to answer it following this method. What are the relevant bits to include for each section?&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;This part is about giving context. Where were you, when was that, and what was your role. Make it short and crisp. Skip any detail about your position that’s not fundamental for understanding the situation.&lt;/p&gt;

&lt;p&gt;After that, it’s time to describe the problem. Remember that you have to make it understandable for people who weren’t there. Talk about the timelines. If you were measuring the problem with some KPI, that’s worth mentioning.&lt;/p&gt;

&lt;p&gt;Be succinct! An interviewer will get frustrated if you bore them with irrelevant details. Practice saying the least possible that is still enough to understand what’s going on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Action
&lt;/h3&gt;

&lt;p&gt;You set up the stages, now it’s time for the important bit. What did &lt;em&gt;you&lt;/em&gt; do? Explain that without domain-specific context or internal terminology. Focus on what &lt;em&gt;you&lt;/em&gt; did. A behavioral question isn’t the time to talk about the team. They are looking to hire &lt;strong&gt;you&lt;/strong&gt; , not your team. Ensure that there’s no ambiguity about that.&lt;/p&gt;

&lt;p&gt;Don’t go too broad with your answer. For a complex project, you did a lot of things. You don’t have time for all of them. Pick the top three that are the most relevant for the question and had the most impact. Again, you’re looking for the right amount of detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;p&gt;The result is where you round up your answer and come to a satisfying conclusion. You did a whole bunch of things. Talk about the outcome. There &lt;strong&gt;has&lt;/strong&gt; to be some outcome. If all your actions changed nothing, find another example.&lt;/p&gt;

&lt;p&gt;Ideally, you’ll have numbers that you can mention. You don’t always have solid, well-measured numbers, but you can make reasoned estimations. Don’t make outlandish claims unless you’re ready to justify them.&lt;/p&gt;

&lt;p&gt;Depending on time, consider including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next Steps: What would come next?&lt;/li&gt;
&lt;li&gt;Scaling: How can you use what you did to scale it to a bigger audience?&lt;/li&gt;
&lt;li&gt;Learnings: What would you do differently next time?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You put all three together, and that’s your answer. See &lt;a href="https://lethain.com/star-method/"&gt;this post&lt;/a&gt; from Will Larson to see an example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Portfolio of Experiences
&lt;/h2&gt;

&lt;p&gt;In my experience, the best way to prepare for the behavioral interview is to build and curate a portfolio of examples based on your experience. There are way too many questions out there. You can’t prepare specific answers for all of them. Instead, I focused on having strong examples that cover multiple behaviors. That way, you can adjust them to the situation instead of scrambling to think of something unique on the spot.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/93a1093d00d8b17b0c168740d51ff694/12609/portfolio.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--krL2Tl5S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/93a1093d00d8b17b0c168740d51ff694/acb04/portfolio.jpg" alt="Portfolio" title="Portfolio" width="750" height="497"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A future portfolio of success&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.amazon.jobs/en/principles"&gt;Amazon Leadership Principles&lt;/a&gt; are a good base. They cover plenty of ground, so you get to think about many different aspects of your previous jobs. I have a table with examples spanning my career that I’ve refined carefully. I usually follow the same approach to extend this table.&lt;/p&gt;

&lt;p&gt;First, I write down a sketch of my answer. Just enough that I know all the points I want to cover. It’s fine to bring your notes to an interview, but don’t read a whole answer straight out of them. Once the case is ready it’s time to polish it! Your first version will inevitably suck. You probably made it too long. Or didn’t make the results clear enough. In any case, you need to iterate relentlessly. Get feedback from somebody you trust for extra perspective.&lt;/p&gt;

&lt;p&gt;Lastly, test it out. Read the scenario aloud to yourself or somebody else. Do a mock interview, or use it in a real interview. While your experience remains the same, your ability to present it will improve massively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some Extra Thoughts
&lt;/h3&gt;

&lt;p&gt;Don’t make stuff up. Honestly, you’ll probably get caught and fail the interview. Even if you somehow put it past your interviewer, you’re setting yourself up for failure.&lt;/p&gt;

&lt;p&gt;Try to cover a decent span of your career. People want to see that you have acquired a broad array of experiences. At the same time, your most recent work is the most valuable. It’s easier to remember, and it’s a closer representation of who you are today. Your strongest examples should come from the last few years.&lt;/p&gt;

&lt;p&gt;You should prepare enough examples. You might get behavioral questions in every interview you do. Expect a couple of them. Talking about the same scenario over and over won’t be beneficial.&lt;/p&gt;

&lt;p&gt;Lastly, don’t limit yourself to positive experiences exclusively. We all have failed at some point. Talking about your failures openly is a great way to show self-reflection and growth. What did you learn, and what would you do differently? Needless to say, don’t confront failure by blaming others. Even if it happens to be true you’re showing a very concerning side to somebody who’s trying to gauge your contributions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure your Outcomes
&lt;/h2&gt;

&lt;p&gt;Let’s be clear: You can’t change your experience. You can make present it better. You can show your ability to reflect and learn. Don’t get discouraged if you think that your examples are too modest.&lt;/p&gt;

&lt;p&gt;If you don’t have impactful examples, think about how to get there over time. Use this to guide your work. If you’re working on a problem at work, go deep and understand its true impact. Seek metrics that will reflect changes. If you’re doing good work, you’ll be able to show it sooner or later. If you somehow didn’t burn all your motivation yet, &lt;a href="https://www.youtube.com/watch?v=PJKYqLP6MRE"&gt;this video&lt;/a&gt; from Jackson Gabbard.&lt;/p&gt;

</description>
      <category>interview</category>
      <category>codingchallenge</category>
      <category>faang</category>
      <category>career</category>
    </item>
    <item>
      <title>The System Design Interview</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Mon, 08 Aug 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/the-system-design-interview-ic9</link>
      <guid>https://dev.to/sirech/the-system-design-interview-ic9</guid>
      <description>&lt;p&gt;System design &lt;a href="https://blog.pragmaticengineer.com/preparing-for-the-systems-design-and-coding-interviews/"&gt;interviews&lt;/a&gt; are a staple of interviewing loops at BigTech. In a system design interview, your job is to design a complex system, such as a video platform like YouTube. You aren’t required to code anything. Instead, you focus on the high-level architecture and discuss aspects like scalability for your design.&lt;/p&gt;

&lt;p&gt;Usually, only somewhat senior candidates get this interview. The assumption is that you need to gather a certain amount of experience before you can talk about designing systems in depth. However, it wouldn’t be out of the ordinary if you haven’t done one of these before. It all depends on your career path. In this article, I want to share what I’ve learned while preparing for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Am I Supposed to Show in a System Design Interview?
&lt;/h2&gt;

&lt;p&gt;In this interview, you show your technological breadth and depth. You consider the different trade-offs and work with the interviewer to get the best solution you can in the allotted time.&lt;/p&gt;

&lt;p&gt;It’s not just about technology, though. The problem is almost always unclear and loosely defined. It’s up to you to bring clarity, understand what to build in more detail, and discuss the alternatives.&lt;/p&gt;

&lt;p&gt;Keep in mind that system design can be decisive in your leveling, even more so than the coding part. Check this &lt;a href="https://www.youtube.com/watch?v=ZgdS0EUmn70"&gt;video&lt;/a&gt; from Jackson Gabbard is an excellent introduction to the topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Solid Foundation
&lt;/h2&gt;

&lt;p&gt;The first layer of preparation is your day-to-day job. If you’re designing systems, you have the opportunity to hone your skills and acquire experience.&lt;/p&gt;

&lt;p&gt;So, practice as much as you can! Write your proposals as &lt;a href="https://blog.pragmaticengineer.com/scaling-engineering-teams-via-writing-things-down-rfcs/"&gt;RFCs&lt;/a&gt; and get feedback from senior engineers in your organization. Review other people’s designs. If this isn’t a well-established process, maybe there’s an opportunity to drive that initiative. It’ll do wonders to your engineering palate. Even if you don’t operate at BigTech scale, it’s a valuable experience.&lt;/p&gt;

&lt;p&gt;If your company doesn’t provide any opportunity to engage in these activities, you should consider moving to a different place. Technical decisions made without any debate? That sounds suspect to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation Materials
&lt;/h2&gt;

&lt;p&gt;&lt;a href="///static/e55306979bed2408d979c36a8d865e60/d0281/ddia.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vsqfOdht--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/e55306979bed2408d979c36a8d865e60/d0281/ddia.png" alt="DDIA" title="DDIA" width="229" height="300"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The bible of System Design&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Designing data-intensive applications (&lt;a href="https://hceris.com/book-review-designing-data-intensive-applications/"&gt;DDIA&lt;/a&gt;) is the canonical book for system design. It’s almost a mandatory read as it covers such a vast amount of topics that are relevant to system design. Additionally, it helps polish your vocabulary to communicate more efficiently with the interviewer.&lt;/p&gt;

&lt;p&gt;Specialized courses are popping up that cover the topic. Alex Wu’s &lt;a href="https://courses.systeminterview.com/"&gt;course&lt;/a&gt; is probably the best and completely worth your money.&lt;/p&gt;

&lt;p&gt;YouTube has a ton of content. For instance, this &lt;a href="https://www.youtube.com/channel/UCRPMAqdtSgd0Ipeef7iFsKw"&gt;channel&lt;/a&gt; is a good source of inspiration. &lt;a href="https://www.youtube.com/nctv"&gt;QCon’s&lt;/a&gt; talks are good as well.&lt;/p&gt;

&lt;p&gt;Lastly, BigTech companies almost always maintain an engineering blog. That’s an excellent resource to understand how they fix their problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practicing Actual Interviews
&lt;/h2&gt;

&lt;p&gt;Once you have a solid base, it’s time to practice. Unlike coding interviews, system design is hard to practice alone. System design interviews are very reliant on timing. You’re looking for an intuitive feeling of how long to spend on each part of the interview. I don’t think you can get the timings right without testing them under realistic conditions.&lt;/p&gt;

&lt;p&gt;Mock interviews are by far the most effective way to practice system design. You can use &lt;a href="https://interviewing.io/"&gt;interviewing.io&lt;/a&gt; if you’re in a rush and don’t mind paying. Or check one of the many interviewing-oriented Discord channels and find a buddy to run some mocks.&lt;/p&gt;

&lt;p&gt;It took me a lot of mental effort to start doing mock interviews. I just found it awkward. I tried to get by doing it by myself. I can tell you it’s not the same. Get over it as fast as possible. It’s worth it.&lt;/p&gt;

&lt;p&gt;Don’t go into a system design interview without practice. You’re almost guaranteed to fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips And Tricks
&lt;/h2&gt;

&lt;p&gt;There’s a vast amount of materials out there. I won’t cover the basics, or tell you to do &lt;a href="https://www.dballona.com/en/system-design-capacity-planning-basics"&gt;capacity planning&lt;/a&gt; or anything like that. Instead, I’m focusing on some realizations that helped me polish my interviews.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Manage Time&lt;/em&gt;. Interviews are shorter than you think. To pass a senior loop, you have to make sure that you handle time effectively&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Reduce Scope&lt;/em&gt;. This is related to time management. System design problems are almost always bigger than what you can handle in an hour. You have to find ways to reduce the scope. Otherwise, you might leave the problem unfinished, or fail to dive into a concrete area.

&lt;ul&gt;
&lt;li&gt;Your main scoping tool is the functional requirements. Don’t define too many of them&lt;/li&gt;
&lt;li&gt;Be prepared to descope during the high-level design. If you realize that you’re trying to do too much, offer to skip some parts or skip details. Whatever you do, don’t risk a half-finished solution&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Don’t repeat yourself&lt;/em&gt;. Train to not repeat the same thing multiple times. You need all the extra time you can buy&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Have an agenda&lt;/em&gt;. I’ll get to this in a second&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;It’s not a quiz&lt;/em&gt;. Some people memorize extremely specific details. That misses the point. I would say that presenting a coherent and reasoned solution is better, even if you skip some details&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Talk about trade-offs&lt;/em&gt;. Every design has pros and cons. You should ensure that you explain the consequences of your decisions and how they inform your design&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Who uses the System?&lt;/em&gt; It’s tempting to dive into replication strategies, partitioning, and a multitude of other technical challenges. But you should always keep the user in your mind. Who is using the system? What’s their success? If I introduce a change in my design, will it result in a better experience for them?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot of these suggestions are very fuzzy. How much scope is too much? How do you know how much time you can spend in an area? That’s why you practice. You need to get a feeling of that, and that’s only happening if you practice in advance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Present a Clear Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="///static/691e38677e523461b4dc7279ffa5e946/f681a/plan.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O1nYKIjN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/691e38677e523461b4dc7279ffa5e946/acb04/plan.jpg" alt="Plan" title="Plan" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;We're getting somewhere here&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There’s so much you can talk about in a system design interview. It’s easy to get lost or start aimlessly rambling. That’s why it’s useful to create a rough outline of the topics you’re going to cover. It has two crucial benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a structure to follow to keep you on track&lt;/li&gt;
&lt;li&gt;You align with the interviewer. If they want to dive into a topic, make sure to integrate that into your plan and cover it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that you should &lt;strong&gt;never&lt;/strong&gt; repeat the same structure for each interview. You’ve got to figure out the relevant parts for the problem at hand and consider your interviewer’s expectations. They surely want to touch on some topics. Don’t ignore those.&lt;/p&gt;

&lt;p&gt;With that being said, this is a sample agenda I’ve used before:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Problem Exploration

&lt;ol&gt;
&lt;li&gt;Functional Requirements&lt;/li&gt;
&lt;li&gt;Cross-Functional Requirements&lt;/li&gt;
&lt;li&gt;What is the success case for the user, and how to measure it&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Plan

&lt;ol&gt;
&lt;li&gt;Propose a list of topics&lt;/li&gt;
&lt;li&gt;Align on items to cover&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Quantitative Analysis

&lt;ol&gt;
&lt;li&gt;QPS&lt;/li&gt;
&lt;li&gt;Data amounts&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;API&lt;/li&gt;
&lt;li&gt;High-Level Design

&lt;ol&gt;
&lt;li&gt;Main services&lt;/li&gt;
&lt;li&gt;Interactions between them&lt;/li&gt;
&lt;li&gt;What kind of data do you produce and store&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Deep Dive

&lt;ol&gt;
&lt;li&gt;Find the most promising topic to dive in&lt;/li&gt;
&lt;li&gt;Go as deep as you can&lt;/li&gt;
&lt;li&gt;Trade-offs!&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Operational concerns

&lt;ol&gt;
&lt;li&gt;Points of failure (error handling)&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;Analytics -&amp;gt; Business metrics&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Scaling Up

&lt;ol&gt;
&lt;li&gt;What are the bottlenecks&lt;/li&gt;
&lt;li&gt;Elasticity&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember that you won’t have time to talk about everything.&lt;/p&gt;

&lt;p&gt;Another way to use an agenda to your benefit is to come back to it as you address different topics. If your design is close to complete, go back to the requirements and check that you covered them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Huge Disclaimer&lt;/strong&gt; : If you sketch a plan, it’s fundamental to make sure you hold yourself to it. If you only manage to run through half of it, you’re pretty much priming your interviewer to fail you. Practice until you can manage the timeslot. Be prepared to descope things as you move along, but don’t ever get to the point where the interviewer cuts in the middle of a sentence with something like “We don’t have any more time, let’s stop here”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logistics
&lt;/h2&gt;

&lt;p&gt;Use a diagramming tool. Get familiar with one so that you don’t waste time trying to draw circles. I like &lt;a href="https://whimsical.com/"&gt;Whimsical&lt;/a&gt; or &lt;a href="https://excalidraw.com/"&gt;Excalidraw&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Write down things! Don’t leave empty boxes. If you’re talking about a topic, write it down, even if only on a high level. The interviewer might go back to the board after the interview. It’s always a challenging balance to strike, as writing absolutely everything you say will slow you down significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it All Together
&lt;/h2&gt;

&lt;p&gt;As you can see, the system design interview focuses on you showing how to apply your experience in technology to fix a nebulous problem in the best way possible. It’s fuzzy and open-ended, and it requires you to think clearly and communicate efficiently. Improve your chances of success by working on all these pieces in advance!&lt;/p&gt;

</description>
      <category>interview</category>
      <category>codingchallenge</category>
      <category>faang</category>
      <category>career</category>
    </item>
    <item>
      <title>Tips for Coding Interviews at FAANG</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Mon, 11 Jul 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/tips-for-coding-interviews-at-faang-3f5d</link>
      <guid>https://dev.to/sirech/tips-for-coding-interviews-at-faang-3f5d</guid>
      <description>&lt;p&gt;Have you ever considered a position in &lt;a href="https://en.wikipedia.org/wiki/Big_Tech"&gt;BigTech&lt;/a&gt; as an engineer? Lots of people do. There’s no shortage of articles where people talk about their experiences.&lt;/p&gt;

&lt;p&gt;If you’ve looked into it, you know that you’ll have to pass a coding interview as part of the process. Possibly multiple rounds, depending on the company. You’re unlikely to get an offer without a decent performance. Better be prepared for them.&lt;/p&gt;

&lt;p&gt;Let’s talk about coding interviews. There are way too many articles about this topic already. I’m assuming you’re familiar with the format already. I’m going to focus on a bunch of things that helped me during the interview process at FAANG.&lt;/p&gt;

&lt;p&gt;If you’re not up to speed, check out &lt;a href="https://blog.pragmaticengineer.com/preparing-for-the-systems-design-and-coding-interviews/#coding-interviews"&gt;this article&lt;/a&gt; from the pragmatic engineer. He’s an invaluable source on all things related to tech.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding Interviews Have Moved Online
&lt;/h2&gt;

&lt;p&gt;Coding interviews are about writing a small program. Typically it’s an algorithmic challenge. Traditionally, you’d do that in person, writing your code on a whiteboard.&lt;/p&gt;

&lt;p&gt;Nowadays, most interviews happen remotely using some online editor. It’s a pretty significant improvement, as coding on a whiteboard is quite uncomfortable. Still, don’t expect much more than simple code highlighting. You don’t get to compile or run your code.&lt;/p&gt;

&lt;p&gt;Thus, the very first thing to do is to get familiar with the environment you’ll be using in the real interview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing for a Coding Interview
&lt;/h2&gt;

&lt;p&gt;It goes without saying, but if you’re going through the process, you’ll have to spend time preparing. If you can’t commit to that, or you fundamentally oppose the idea, then you should skip the whole thing. I don’t think you can realistically pass a FAANG interview loop without any preparation.&lt;/p&gt;

&lt;p&gt;With that in mind, here are six tips for a more successful coding interview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Right Amount of Grinding&lt;/li&gt;
&lt;li&gt;Speed is Key&lt;/li&gt;
&lt;li&gt;Share your Thoughts&lt;/li&gt;
&lt;li&gt;Get Used to Write Readable Code&lt;/li&gt;
&lt;li&gt;A Clear Structure&lt;/li&gt;
&lt;li&gt;Don’t Give Up&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Right Amount of Grinding
&lt;/h3&gt;

&lt;p&gt;&lt;a href="///static/2505631315ee2ca9932729f3065bc97a/78bce/grinding.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xBZuKz-P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/2505631315ee2ca9932729f3065bc97a/acb04/grinding.jpg" alt="Grinding" title="Grinding" width="750" height="485"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Putting that subscription to use&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There’s a whole industry built around preparing for technical interviews. Books, videos, courses, websites, you name it. I would stick to &lt;a href="https://leetcode.com/"&gt;LeetCode&lt;/a&gt;. LeetCode is a highly convenient place to practice exercises similar to the ones you’ll encounter.&lt;/p&gt;

&lt;p&gt;LeetCode has a ton of exercises, though. It’s easy to get lost. You read horror stories of people that spent months doing it full time. I don’t think you need to get to those extremes to have success.&lt;/p&gt;

&lt;p&gt;Aim for breadth. I used LeetCode to develop a broad portfolio of techniques you can apply to any problem. Some concrete recommendations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cover a variety of structures, like Arrays, Hashes, Linked Lists, Heaps, Trees, or Graphs&lt;/li&gt;
&lt;li&gt;Cover a variety of techniques, like Binary Search, BFS/DFS, Sort, Backtracking, or Sliding Windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other structures like Tries or &lt;a href="https://en.wikipedia.org/wiki/Disjoint_sets"&gt;Disjoint Sets&lt;/a&gt; make some difficult problems super easy. It’s never a bad idea to expand your toolkit.&lt;/p&gt;

&lt;p&gt;Certain algorithms are just too hard to implement in the context of an interview. Nobody other than a sadist will ask you to write a Red-Black Tree in an interview. Then you have some edge cases, like Dynamic Programming. Google is supposed to like them a lot. Get familiar with some of them, but remember that plenty of people struggle mightily solving them.&lt;/p&gt;

&lt;p&gt;LeetCode categorizes problems as &lt;em&gt;easy/medium/hard&lt;/em&gt;. I doubt you will pass an interview for BigTech if you can only handle easy problems. If you are good at finishing medium problems, you’re probably good to go. If you can reliably solve hard problems under the constraints of an interview you probably don’t need my advice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Speed is Key
&lt;/h3&gt;

&lt;p&gt;&lt;a href="///static/0db5e10bee26e511d7e5ac70c44fd24a/d2602/kotlin.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PHCQkkLD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/0db5e10bee26e511d7e5ac70c44fd24a/acb04/kotlin.jpg" alt="Kotlin" title="Kotlin" width="750" height="563"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The king of terse code&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Interviews are short. You have about 15-20 minutes per problem to solve two problems, at best. Minimizing the amount of typing gives you back some valuable time.&lt;/p&gt;

&lt;p&gt;For that reason, I recommend using the highest-level language you’re comfortable with. I don’t know if esoteric languages are a good bet, though.&lt;/p&gt;

&lt;p&gt;Python is a common choice because it’s both popular and high-level. I’m not a C++ person, but it feels a bit too low level. I find Java too verbose (consider using a newer version if you pick it). I don’t like JavaScript as it doesn’t have a very comprehensive standard library.&lt;/p&gt;

&lt;p&gt;I ended up using Kotlin. Similar to Java, but much more succinct. You can use all the standard libraries. I like the language a lot, so it made my preparation easier. I think you should stick to one language, though. Most companies are fairly accommodating in that respect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Share your Thoughts
&lt;/h3&gt;

&lt;p&gt;You can’t solve problems silently. Even if you’re correct, you might lose your interviewer. However, don’t mistake this ubiquitous advice for constant talking. Just avoiding silence isn’t good enough.&lt;/p&gt;

&lt;p&gt;You should talk about the options that you’re considering. What are the tradeoffs? Maybe you have a great idea that won’t fit within the interview. Share your thoughts and let the interviewer participate. Many are happy to support you and offer valuable tips and input.&lt;/p&gt;

&lt;p&gt;Once you start coding, shift to discuss why you are doing things. Explain the choices you make in data structures. Walk the interviewer through the structure of the code. Show her a coherent path.&lt;/p&gt;

&lt;p&gt;Talking while coding isn’t easy to practice just by doing LeetCode. Consider walking a friend through a problem, or doing a mock interview.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Used to Writing Readable Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="///static/cfc3eed1f7a6842ba3bae3045f3c5cda/fc9e0/readable.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kKLIWnB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/cfc3eed1f7a6842ba3bae3045f3c5cda/acb04/readable.jpg" alt="Readable" title="Readable" width="750" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Good variable naming&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The pressure of getting something done quickly will tempt you to take shortcuts. Don’t do that.&lt;/p&gt;

&lt;p&gt;Use good variable names and split chunks into functions. Write idiomatic code. If needed, add a comment or two. It will help you, and it will help the interviewer evaluate you.&lt;/p&gt;

&lt;p&gt;Splitting the code has another benefit; you can tackle things in order of importance. Most interviewers won’t care if you leave boilerplate functions unimplemented. I’ve had interviewers that completed some of my methods while I was writing the core part.&lt;/p&gt;

&lt;p&gt;You won’t have linters or formatters to help produce readable output. It’s on you to get this ingrained as a habit. Doing it naturally means you won’t have to focus on it, which leaves space to focus on other meatier parts of the interview.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Clear Structure
&lt;/h3&gt;

&lt;p&gt;Following a clear structure helped me a lot. If you get nervous you might forget important steps. Take this as an example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand the problem. State it in your own words.&lt;/li&gt;
&lt;li&gt;Input/Output. Write down some inputs and the outputs. Think of edge cases.&lt;/li&gt;
&lt;li&gt;Approach. Think of an approach, and explain the tradeoffs.&lt;/li&gt;
&lt;li&gt;Code the solution&lt;/li&gt;
&lt;li&gt;Read through your solution carefully. Spot errors&lt;/li&gt;
&lt;li&gt;Test the code. Run a sample input manually&lt;/li&gt;
&lt;li&gt;How does the solution perform? Use the O-notation, for time and space&lt;/li&gt;
&lt;li&gt;Can you improve it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice how coding is just one among many steps. That’s comparable to how you’d approach a problem in real life.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/f92eeacb10aa1ba2e28e87a8cd4ee17d/fd63d/discipline.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cy-zRxDD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/f92eeacb10aa1ba2e28e87a8cd4ee17d/acb04/discipline.jpg" alt="Discipline" title="Discipline" width="750" height="483"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Programmers estimating the time complexity of a double loop&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Being disciplined is key. It gives you time to explore the boundaries of the problem. Maybe you misunderstood the problem. Establishing a conversation helps you work on what the interviewer wants, not what you have in mind. Depending on seniority, you won’t pass the interview if you only code a solution without thinking about edge cases and testing the solution by yourself.&lt;/p&gt;

&lt;p&gt;If you don’t find the optimal approach, take any solution that you can think of and iterate. Iterate continuously until you get to a good place. Clear code and discipline help tremendously here.&lt;/p&gt;

&lt;p&gt;Given that you’re diligently preparing, there’s a chance that you get a problem that you’ve seen before. Don’t pretend to struggle and “magically” find the optimal solution. You’ll make an ass of yourself and fail in the process. Be honest in what you know. Let the interviewer change the problem if they need to, but don’t force the issue yourself.&lt;/p&gt;

&lt;p&gt;Learn to do reasonable O-notation estimations on the fly. Nobody is going to expect hard proof in the middle of the interview. A few heuristics go a long way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t Give Up!
&lt;/h3&gt;

&lt;p&gt;If you get stuck, don’t panic. Keep trying things, and keep voicing your thoughts. A naive solution is better than no solution. You might think that you’re bombing the interview, but some problems are too big by design.&lt;/p&gt;

&lt;p&gt;If you’re running out of time, explain how you would continue with the parts that are missing. Whatever you do, don’t give up. Even if your performance isn’t great, show as much as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I Always Get Nervous During Coding Interviews?
&lt;/h2&gt;

&lt;p&gt;Welcome to the club! Very few people are naturally good at this. An interview is a stressful situation, no matter what. Preparing well gives you the backbone to rely on when things get rough. Interviewers want you to succeed, for the most part.&lt;/p&gt;

&lt;p&gt;Even if you are well prepared, you’ll fail some interviews miserably. Shit happens. Don’t take it as a personal failure. Everybody has gone through that.&lt;/p&gt;

</description>
      <category>interview</category>
      <category>codingchallenge</category>
      <category>faang</category>
      <category>career</category>
    </item>
    <item>
      <title>Book Review: Site Reliability Workbook</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Mon, 23 May 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/book-review-site-reliability-workbook-436</link>
      <guid>https://dev.to/sirech/book-review-site-reliability-workbook-436</guid>
      <description>&lt;p&gt;&lt;a href="///static/877fe33b02bca4b4f35c2832599d2ea3/09d21/cover.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gG_U-Cw4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/877fe33b02bca4b4f35c2832599d2ea3/09d21/cover.jpg" alt="Site Reliability Workbook" title="Site Reliability Workbook" width="540" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sre.google/workbook/table-of-contents/"&gt;Site Reliability Workbook&lt;/a&gt; is the successor of &lt;a href="https://sre.google/sre-book/table-of-contents/"&gt;Site Reliability Engineering&lt;/a&gt;. In the first book, Google introduced its vision of site reliability to the world, launching countless discussions about the distinction between SRE and DevOps.&lt;/p&gt;

&lt;p&gt;One common criticism of that treaty was that it was hard to apply for organizations with fewer resources than Google. The second book aims to fix that. This time around, they’re focusing on discussing practices that anybody can implement to become more effective at operating live systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Much Content
&lt;/h2&gt;

&lt;p&gt;This book is a gigantic &lt;code&gt;HOWTO&lt;/code&gt; on how to implement SRE. There’s a good amount of theory, there’s is source code, and there are case studies. It covers three areas throughout its almost 500 pages:&lt;/p&gt;

&lt;h3&gt;
  
  
  Foundations
&lt;/h3&gt;

&lt;p&gt;Foundations are the base building blocks you’ll use daily if you adopt an SRE approach. SLOs, monitoring, toil, and a call for simplicity in software architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practices
&lt;/h3&gt;

&lt;p&gt;What kind of practices help to continuously improve and iterate? Having a healthy On-Call rotation for one. Handling incidents in general features prominently, including reflecting on causes and next steps in postmortems.&lt;/p&gt;

&lt;p&gt;Interestingly, how to handle configuration is another big topic here. I was pleasantly surprised to learn that Google emphasizes manageable configuration definitions. They mention &lt;a href="https://hceris.com/templating-concourse-pipelines-with-jsonnet/"&gt;jsonnet&lt;/a&gt; as a tool to handle that complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Processes
&lt;/h3&gt;

&lt;p&gt;The last part of the book is about processes. How should an SRE team engage with other teams? How do they recognize if the time for collaboration is over? In a way, this section reminds me of another book, &lt;a href="https://hceris.com/book-review-team-topologies/"&gt;team topologies&lt;/a&gt;. I’ve lost count of how many times I’ve said that a platform team and an enablement team have completely different mandates. This part really resonated with me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Talk About SLOs
&lt;/h2&gt;

&lt;p&gt;Chapter 5 focuses on &lt;a href="https://sre.google/sre-book/service-level-objectives/"&gt;service level objectives (SLOs)&lt;/a&gt;. It’s by far my favorite chapter. I’ve re-read it over and over. I’ve spent a lot of time thinking about alerts over the past year.&lt;/p&gt;

&lt;p&gt;Understanding how to implement &lt;a href="https://hceris.com/multiwindow-multi-burn-rate-alerts-in-datadog/"&gt;multiwindow, multi-burn-rate alerts&lt;/a&gt; improved my quality of life massively when I was on a project that suffered from poor alerts. And let me tell you, it’s not an easy thing to understand. Don’t underestimate the complexity behind implementing high-quality alerts.&lt;/p&gt;

&lt;p&gt;This book is the best source to understand SLOs. It’s worth getting just for this chapter alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;This book covers a lot of ground. There’s a lot to unpack, much of it extremely actionable. I’ve found myself coming back to it a lot lately. It seems to have more sticking power than the first book. I think it’s a very recommendable read. It gets ⭐⭐⭐⭐ stars from me.&lt;/p&gt;

</description>
      <category>bookreview</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>alerts</category>
    </item>
    <item>
      <title>Making a Microservice More Resilient Against Downstream Failure</title>
      <dc:creator>Mario Fernández</dc:creator>
      <pubDate>Sun, 08 May 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/sirech/making-a-microservice-more-resilient-against-downstream-failure-1b5k</link>
      <guid>https://dev.to/sirech/making-a-microservice-more-resilient-against-downstream-failure-1b5k</guid>
      <description>&lt;p&gt;I like thinking about monitoring and &lt;a href="https://hceris.com/monitoring-alerts-that-dont-suck/"&gt;alerting&lt;/a&gt; a lot. &lt;a href="https://hceris.com/multiwindow-multi-burn-rate-alerts-in-datadog/"&gt;SLOs&lt;/a&gt; have been one of my latest obsessions over the past few months.&lt;/p&gt;

&lt;p&gt;However, all these metrics are worthless if left unattended! Worse than worthless. If you have comprehensive alerts that don’t get fixed, you’ll get swamped by a barrage of alerts.&lt;/p&gt;

&lt;p&gt;That’s precisely what I want to talk about. This post covers making services more tolerant against downstream failures, using the wonderful &lt;a href="https://resilience4j.readme.io/"&gt;resilience4j&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instability Can Ruin Your Day
&lt;/h2&gt;

&lt;p&gt;In my last project, I maintained a service with high visibility. The service didn’t own any data, relying instead on several downstream dependencies. Sadly, these dependencies were very unstable and experienced frequent downtime. The issues propagated to our service, causing errors. It made us look bad. Check these error spikes:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/7f3bcb3cae324c2e4659cb809e83ecb3/e67a8/errors.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UUQKo4Aa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/7f3bcb3cae324c2e4659cb809e83ecb3/1d69c/errors.png" alt="Error Rate" title="Error Rate" width="750" height="459"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Shit is hitting the fan&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not only were our users getting a mediocre experience, but our &lt;a href="https://github.com/sirech/talks/blob/master/2021-11-devoxx-humane_on_call_alerting_doesnt_have_to_be_painful.pdf"&gt;On-Call&lt;/a&gt; rotations were becoming a shitshow. We &lt;em&gt;had&lt;/em&gt; to do something about it. It was leading to a dangerous spiral that could only end in burn-out.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enter Resilience4j
&lt;/h2&gt;

&lt;p&gt;Our service is written in Java. That makes &lt;code&gt;resilience4j&lt;/code&gt; a natural fit. In case you don’t know, it’s a library written by Netflix focused on fault tolerance. As a bonus, it’s based on &lt;a href="https://www.vavr.io/"&gt;Vavr&lt;/a&gt;. Thus, it benefits from things like the &lt;a href="https://hceris.com/kotlin-either-types-instead-of-exceptions/"&gt;Either type&lt;/a&gt; and all that good stuff. It’s right up my alley.&lt;/p&gt;

&lt;p&gt;To prevent the nasty error spikes I showed above, we’re focusing on two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using resilience operators to make our microservice a better-behaved citizen&lt;/li&gt;
&lt;li&gt;Building a fallback cache to prevent downstream errors from affecting our users&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Using Resilience Operators
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;resilience4j&lt;/code&gt; provides a bunch of &lt;a href="https://resilience4j.readme.io/docs"&gt;operators&lt;/a&gt; out of the box that increases the fault tolerance of your remote calls. One big plus of this library is its composability. There’s little difference between using a &lt;a href="https://resilience4j.readme.io/docs/retry"&gt;Retry&lt;/a&gt; alone or piping other operators like a &lt;a href="https://resilience4j.readme.io/docs/circuitbreaker"&gt;CircuitBreaker&lt;/a&gt;. I’m not getting into the details of how they work, head over the documentation to get more details.&lt;/p&gt;

&lt;p&gt;If you use &lt;a href="https://spring.io/projects/spring-boot"&gt;Spring Boot&lt;/a&gt;, there’s support for using annotations. There’s always support for annotations if SpringBoot is involved. Interestingly enough, I feel the annotations create a bit too much duplication. See, I wanted to apply a common set of operators to six or seven remote calls. Annotating the methods and adding the fallbacks led to a messy solution.&lt;/p&gt;

&lt;p&gt;Instead, I built a small abstraction, a &lt;em&gt;FallbackCache&lt;/em&gt;. Before we consider the caching part, let’s focus on instantiating these operators. The code is quite declarative:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Retry&lt;/span&gt; &lt;span class="nf"&gt;getRetry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MeterRegistry&lt;/span&gt; &lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;RetryRegistry&lt;/span&gt; &lt;span class="n"&gt;retryRegistry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RetryRegistry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofDefaults&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;TaggedRetryMetrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofRetryRegistry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retryRegistry&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;bindTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;retryRegistry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;CircuitBreaker&lt;/span&gt; &lt;span class="nf"&gt;getCircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MeterRegistry&lt;/span&gt; &lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;CircuitBreakerRegistry&lt;/span&gt; &lt;span class="n"&gt;circuitBreakerRegistry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CircuitBreakerRegistry&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofDefaults&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;TaggedCircuitBreakerMetrics&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofCircuitBreakerRegistry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;circuitBreakerRegistry&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;bindTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;circuitBreakerRegistry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a vast amount of settings that you can configure. The default settings work well to get started. On top of that, I’m adding metrics for &lt;a href="https://micrometer.io/"&gt;micrometer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Fallback Cache
&lt;/h2&gt;

&lt;p&gt;Building resilience operators is only one part of the equation. Yes, we’re retrying failed requests automatically. Thanks to the circuit breaker we won’t &lt;a href="https://en.wikipedia.org/wiki/Denial-of-service_attack"&gt;DDOS&lt;/a&gt; downstream services. But the user won’t care. As it is, the errors propagate back to them.&lt;/p&gt;

&lt;p&gt;My answer is a fallback cache. The flow is as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/fd7c91df342709089cd09900c79b04a6/7db30/degradation.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KI-X9kYH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://hceris.com/static/fd7c91df342709089cd09900c79b04a6/1d69c/degradation.png" alt="Fallback flow" title="Fallback flow" width="750" height="575"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;That's a happy user&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This boils down to three steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make a call to the downstream service with retries and a circuit breaker&lt;/li&gt;
&lt;li&gt;If the call works, store the result in a cache and return it&lt;/li&gt;
&lt;li&gt;If the call fails, use the cache to serve a fallback so that the user experience isn’t compromised&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before you ask, caching proactively wasn’t an option as we didn’t have a way to invalidate the cache when the underlying data changed. Anyhow, these three steps map nicely to a class with the following methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SyncFallbackCache&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Cacheable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractFallbackCache&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keySupplier&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valueSupplier&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getAndCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valueSupplier&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getFromCacheOrThrow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s go one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making the Call
&lt;/h3&gt;

&lt;p&gt;The fallback cache doesn’t do anything on its own, as it’s rather a wrapper. We use a &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html"&gt;Supplier&lt;/a&gt; to pass the operation to perform. We need a key to identify the element in the cache, which uses another supplier for extra flexibility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keySupplier&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valueSupplier&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;decoratedSupplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decorators&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSupplier&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getAndCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valueSupplier&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withRetry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withCircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;decorate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keySupplier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Try&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSupplier&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decoratedSupplier&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;recover&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getFromCacheOrThrow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We decorate the supplier with our operators. If the call works, we return the result. If not, there’s a &lt;a href="https://www.javadoc.io/doc/io.vavr/vavr/0.9.2/io/vavr/control/Try.html"&gt;Try&lt;/a&gt; wrapping it that looks for something to serve from the cache. An empty cache means we’re out of options, and we can only propagate the error upstream.&lt;/p&gt;

&lt;h3&gt;
  
  
  Store the Result
&lt;/h3&gt;

&lt;p&gt;Whenever we get a valid result, we store it in the cache. Let’s assume that &lt;code&gt;valueSupplier.get()&lt;/code&gt; returns without any errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getAndCache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valueSupplier&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/*
    This has the disadvantage that the [get result, cache it] is not atomic. So if two requests try to update the same key at the same time, it might create an undetermined result.

    However, two calls to the same service should return the same value, so we should be able to live with that.

    This is not happening inside the compute method anymore due to problems acquiring the lock that led to significant timeouts.
   */&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valueSupplier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Try&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;recover&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Could not save result to cache"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Cacheable:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This action should be as seamless as possible. We want to avoid blocking anything while we save the data. Moreover, we swallow any error that happens while saving. Failing to save to the cache shouldn’t result in a failed request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the Fallback
&lt;/h3&gt;

&lt;p&gt;If the supplier didn’t work, our last hope is to find some content in the cache for the associated key. We can show valid, albeit possibly outdated, information to the user. A cache miss ends up with the original exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getFromCacheOrThrow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ifPresent&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FallbackCache[%s] got cached value"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Cacheable:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FallbackCache[%s] got an error without a cached value"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt;
                &lt;span class="n"&gt;exception&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
          &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Caller’s Perspective
&lt;/h3&gt;

&lt;p&gt;As a user, I need to instantiate a &lt;code&gt;SyncFallbackCache&lt;/code&gt; and call the public method with the operation I want to safeguard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;SyncFallbackCache&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SupplierUserPermission&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SupplierUserPermission&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getPermissions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;supplierId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id:%s;suId:%s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;supplierId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
      &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserPermissions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;supplierId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSupplierUserMyInformation&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPermissions&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we don’t need to know about what’s happening underneath. It’s pretty nifty. You could argue that the return type isn’t explicit enough, as the method may throw an exception that’s not part of the signature. An alternative is to model it with an &lt;a href="https://www.javadoc.io/doc/io.vavr/vavr/0.10.0/io/vavr/control/Either.html"&gt;Either&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where’s the Cache?
&lt;/h2&gt;

&lt;p&gt;I haven’t spoken about the cache. The easiest alternative is using an in-memory cache like &lt;a href="https://github.com/ben-manes/caffeine"&gt;Caffeine&lt;/a&gt;. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MeterRegistry&lt;/span&gt; &lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Caffeine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;recordStats&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;expireAfterWrite&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofHours&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maximumSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nc"&gt;CaffeineCacheMetrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;monitor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is convenient yet flawed. Our application runs as a container. Every time it’s restarted, the cache is wiped out. It leads to a bad hit rate percentage, which hovered around 65-70%. That’s not great for a cache and still propagates way too many failures to the end-user.&lt;/p&gt;

&lt;p&gt;We switched to a persistent cache based on &lt;a href="https://aerospike.com/"&gt;Aerospike&lt;/a&gt; to mitigate the problem. &lt;em&gt;SpringBoot&lt;/em&gt; has some integrations to make this easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;NavigationRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt;
    &lt;span class="nc"&gt;AerospikeRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CachedNavigation&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="nd"&gt;@Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"navigation_CachedNavigationMenu"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CachedNavigation&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Cacheable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LegacyNavMenuItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Id&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LegacyNavMenuItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;navigation&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LegacyNavMenuItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;navigation&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the cache for failure scenarios means invalidation isn’t that relevant. The persistent cache made a tangible difference that brought our hit rate percentage to the high 90s. That’s a lot better, isn’t it?&lt;/p&gt;

&lt;h2&gt;
  
  
  A Journey With a Happy Ending
&lt;/h2&gt;

&lt;p&gt;Was all this effort &lt;em&gt;worth it&lt;/em&gt;? Hell, yes. Our error rate went from 2% to 0.03%. We’ve set an SLO for the service’s availability of 99,95%. Our rotations became significantly smoother. I had so much time available that I could write blog posts about it!&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>monitoring</category>
      <category>datadog</category>
      <category>netflix</category>
    </item>
  </channel>
</rss>
