<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Daniele Margutti</title>
 <link href="https://www.danielemargutti.com/atom.xml" rel="self"/>
 <link href="https://www.danielemargutti.com/"/>
 <updated>2025-11-17T19:37:09+00:00</updated>
 <id>https://www.danielemargutti.com</id>
 <author>
   <name></name>
   <email></email>
 </author>

 
 <entry>
   <title>HTTP Client for Swift</title>
   <link href="https://www.danielemargutti.com/2025/06/18/http-client-swift-1/"/>
   <updated>2025-06-18T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2025/06/18/http-client-swift-1</id>
   <content type="html">&lt;p&gt;Oh dear, just what I needed… &lt;em&gt;another delightful request for a refactor!&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Oh no! Yet another refactor request!</title>
   <link href="https://www.danielemargutti.com/2025/02/14/yet-another-refactor/"/>
   <updated>2025-02-14T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2025/02/14/yet-another-refactor</id>
   <content type="html">&lt;p&gt;Oh dear, just what I needed… &lt;em&gt;another delightful request for a refactor!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can bet this is the first—and probably the second—thought that crosses the mind of any manager or engineering lead when some dev pops up with a shiny refactor idea during any brainstorming or planning session. 
It’s like, &lt;em&gt;“Oh great, here we go again!”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s because there are few—like, really few—valid reasons for something to deserve a refactor.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But hey, that’s a topic for another post!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anyway, getting management to understand that you need a significant amount of time for a meaningful code refactor is quite hard.&lt;/p&gt;

&lt;p&gt;It’s basically a negotiation, so having your homework done is key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Despite what you think, for the company, initiating a refactor is seen as a risky move that takes time away from - literally - any other activity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And let’s be honest, it usually involves something that actually works—albeit in a messy, ugly, and barely maintainable way. But hey, after a lot of patches, &lt;em&gt;it still delivers the goods!&lt;/em&gt;&lt;br /&gt;
It’s like trying to convince someone to fix a leaky sink when the water is still flowing.&lt;/p&gt;

&lt;p&gt;You know it’ll be better in the long run, but getting buy-in is no walk in the park!&lt;/p&gt;

&lt;h2 id=&quot;who-do-you-talk-to&quot;&gt;Who do you talk to?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Your primary goal is to make your needs align with the person you’re talking to.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Speaking the same language is crucial: for instance, someone who isn’t very technical won’t care much about the benefits of clean code, but they will likely be interested in how performance will change as a result of this activity.&lt;/p&gt;

&lt;p&gt;Use concrete examples to explain how the current codebase is holding the team back, how refactoring can improve the status quo, and when applicable translate the benefits to hours or money.&lt;/p&gt;

&lt;h2 id=&quot;the-yourney-so-far&quot;&gt;The yourney so far&lt;/h2&gt;

&lt;p&gt;One of the big questions non technical execs have is “why did the codebase end up in this state in the first place”. Depending on who your audience is it may be important to have this information in your presentation.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Knowing what led to the current situation (when possible) shows a deep understanding of the problem and boosts your reliability in activities that can help set things straight.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Something like that adds context and justification that a non technical execs will understand.&lt;/p&gt;

&lt;h2 id=&quot;the-evidencies&quot;&gt;The Evidencies&lt;/h2&gt;

&lt;p&gt;Refactoring should be treated just like any other project. 
Don’t just stop at chit-chat: if you can, strengthen your case with some solid data. 
Metrics, benchmarks, user feedback, and even downtimes are just a few nuggets you can pull out to showcase the potential benefits of a refactor.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The more evidence of possible improvements you have, the better you can paint the picture of why refactor is crucial (ROI / Return Of Investment).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s all about making your argument as bulletproof as possible!&lt;br /&gt;
After all, numbers don’t lie, and they can help turn skeptics into supporters.&lt;/p&gt;

&lt;p&gt;Be sure to show how the benefits of the change.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;How will reduce security risk leading to a possible litigation&lt;/li&gt;
  &lt;li&gt;How many hours will be saved on future development&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-plan&quot;&gt;The Plan&lt;/h2&gt;

&lt;p&gt;Make sure you have a rough plan. Of course, you won’t stick to it perfectly, but that’s okay because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;It’ll help your conversation partner grasp the effort involved&lt;/strong&gt;; especially for those who aren’t technical, it’ll make it easier to understand the scope of the work.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It’ll allow you to really get a handle on the problem, forcing you to break it down into smaller tasks&lt;/strong&gt;, which makes it easier to delegate to the team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you can show the problem and make a detailed plan to solve it, it’s hard to get no as an answer.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Anyway, the best way to avoid huge refactoring is to make refactoring part of your daily/sprint routine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;one-step-at-time&quot;&gt;One step at time&lt;/h2&gt;

&lt;p&gt;A big refactor isn’t something you can whip up in a day, and management might need some time to wrap their heads around it.&lt;br /&gt;
Stay patient, keep pushing, and make sure to keep the communication flowing!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Fixing the Xcode 16 LLDB error &quot;Couldn’t realize type of self”</title>
   <link href="https://www.danielemargutti.com/2024/12/06/xcode16-couldnt-realize-type-of-self/"/>
   <updated>2024-12-06T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2024/12/06/xcode16-couldnt-realize-type-of-self</id>
   <content type="html">&lt;p&gt;Programming on iOS has never just been about chasing after Apple’s new APIs; often—indeed, more than necessary—it involves implementing more or less creative workarounds to overcome issues that arise specifically with the toolchains, Xcode being the primary one.&lt;/p&gt;

&lt;p&gt;Since the introduction of Swift—ten years ago now—the quality of debugging apps with complex architectures has always been a battleground. From time to time, we find ourselves dealing with a debugger that just won’t cooperate.&lt;/p&gt;

&lt;p&gt;The latest issue is with Xcode 16.0; basically, the error pops up when you try to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;po&lt;/code&gt; &lt;variable&gt;:&lt;/variable&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;error: type for self cannot be reconstructed: type for typename &quot;$s15IndomioControls17AdsCollectionViewCD&quot; was not found (cached)
error: Couldn&apos;t realize Swift AST type of self. Hint: using `v` to directly inspect variables and fields may still work.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The error appears only when you set a breakpoint in a Swift files.&lt;br /&gt;
There is no issues while debugging Obj-C file (&lt;em&gt;I miss you bro&lt;/em&gt;).&lt;br /&gt;
Moreover it only affects the debugging part, but it doesn’t impact the compilation or the runtime execution of the code.&lt;/p&gt;

&lt;p&gt;You’re really just left unable to debug the code—nothing too serious, right? I mean, who needs a debugger anyway? You can always just print stuff out like it’s the good old days!&lt;/p&gt;

&lt;p&gt;I know you’re just itching for the solution; so if you’re about to lose your mind and really can’t be bothered to learn anything new, go ahead and skip straight to the last chapter of this article.&lt;/p&gt;

&lt;h2 id=&quot;p-po-v-what-the-heck&quot;&gt;p, po, v… what the heck?&lt;/h2&gt;

&lt;p&gt;In our case, the problem occurs for all the modules (frameworks imported via SPM) linked to the main project. It was impossible to debug any variable, even when trying with the commands &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt; (and, to top it off, the LLDB server crashed more than once).&lt;/p&gt;

&lt;p&gt;The funny thing is that in the Variable View of Xcode, the variables were almost always visible.&lt;br /&gt;
&lt;strong&gt;Hint: you can ge the same output of the Variable View by using the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame variable &amp;lt;name_variable&amp;gt;&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But, what’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;po&lt;/code&gt; and why isn’t working?&lt;br /&gt;
Before that we need to briefly talk about LLDB.&lt;/p&gt;

&lt;h2 id=&quot;how-lldb-is-able-to-format-variables&quot;&gt;How LLDB is able to format variables&lt;/h2&gt;

&lt;p&gt;LLDB isn’t just a debugger: it’s also a compiler—yep!&lt;br /&gt;
With copies of both the Swift and Clang compilers, it can evaluate complex expressions (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;po&lt;/code&gt; being just aliases) and alter the program’s state using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But how does a debugger format a variable? Let’s consider the following statement:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we hit a breakpoint in LLDB and try to print the content of a variable in a raw way, we get, as expected, a bunch of bytes:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;variable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;L&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// obtain the memory address&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x0000000100008000&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mem&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0000000100008000&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// print the address content&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x100008000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;57&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eb&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;Hello&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;World&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.....&lt;/span&gt;
   &lt;span class=&quot;mh&quot;&gt;0x100008010&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;................&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Not very helpful, right?&lt;br /&gt;
To provide a pretty printed format of the data, &lt;strong&gt;LLDB needs to know the types of these data&lt;/strong&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dictionary&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyClass&lt;/code&gt; etc.).&lt;/p&gt;

&lt;p&gt;Since Xcode 14.x, this information comes from 2 different side, which explains why different commands may work or not:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;DEBUGGER SIDE&lt;/strong&gt; &lt;br /&gt;
  Here the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame&lt;/code&gt; commands lives.&lt;br /&gt;
  Type information is obtained from Debug Info (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.o&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.dSYM&lt;/code&gt;) and by using Swift Reflection.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;COMPILER SIDE&lt;/strong&gt;&lt;br /&gt;
Hhere the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;po&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expr&lt;/code&gt; commands lives.  &lt;br /&gt;
Type information is obtained from Modules: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.swiftmodule&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.modulemap&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.h&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bridging-header.h&lt;/code&gt;.?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Modules are how the compilers organizes type declarations&lt;/strong&gt;.&lt;br /&gt;
But we’ll get back to this in a bit; have you ever heard of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swift-healthcheck&lt;/code&gt;?&lt;/p&gt;

&lt;h2 id=&quot;swift-healthcheck-to-the-rescue&quot;&gt;swift-healthcheck to the rescue!&lt;/h2&gt;

&lt;p&gt;This command was added a couple of years ago and is the first thing to keep in mind when analyzing a problem related to modules.&lt;/p&gt;

&lt;p&gt;If we execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swift-healthcheck&lt;/code&gt; after a problem with LLDB occour we can get access to a log the inner process of the Swift expression evaluator.&lt;/p&gt;

&lt;p&gt;Let’s get back to our problem and try executing the command:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;po&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adId&lt;/span&gt;
   &lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cannot&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;reconstructed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typename&lt;/span&gt; 
   &lt;span class=&quot;s&quot;&gt;&quot;$s11IndomioCore7HTTPOpsO8AdDetailCD&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;found&lt;/span&gt;
   &lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Couldn&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;realize&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Swift&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Hint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;directly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inspect&lt;/span&gt; 
   &lt;span class=&quot;n&quot;&gt;variables&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;may&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;still&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;swift&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;healthcheck&lt;/span&gt;
   &lt;span class=&quot;kt&quot;&gt;Health&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;check&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;written&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/var/folders/fp/h_f5_67x16bbsfp5g4f76jc40000gn/T/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;
   &lt;span class=&quot;sr&quot;&gt;/72168/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lldb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;healthcheck&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ff2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we open the file mentioned, we find a bunch of information that can help us out.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;==== LLDB swift-healthcheck log. ===
...
SwiftASTContextForExpressions(module: &quot;IndomioCore&quot;, cu: &quot;HTTPOps+Ad.swift&quot;)::LoadOneModule() -- Missing Swift module or Clang module found for &quot;IndomioCommons&quot;, &quot;imported&quot; via SwiftDWARFImporterDelegate. Hint: Register Swift modules with the linker using -add_ast_path.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we said, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndomioCore&lt;/code&gt; is an internal framework and the error is telling us that for some reason, it failed to import the related module.&lt;br /&gt;
This missing module is a problem because LLDB can’t understand the data type related to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self&lt;/code&gt;, and as a result, it can’t format it.&lt;/p&gt;

&lt;h2 id=&quot;where-modules-come-from-and-who-register-them&quot;&gt;Where Modules come from and who register them?&lt;/h2&gt;

&lt;p&gt;Each module contains the interfaces for its own APIs.&lt;br /&gt;
Generally speaking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System Frameworks&lt;/strong&gt;&lt;br /&gt;
Modules are integrated within the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sdk&lt;/code&gt; file (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MacOSX.sdk&lt;/code&gt;).
LLDB will find a matching SDK to read them from as it’s attacching to your program on a debug session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;External Frameworks&lt;/strong&gt;&lt;br /&gt;
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.dSYM&lt;/code&gt; package generated by the build system usually contains all the associated modules (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.swiftmodule&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bridging-header.h&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.swiftinterface&lt;/code&gt;) related to the frameworks compiled by the target itself.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dsymutil&lt;/code&gt; can package a debug info archive called a .dSYM bundle for every dynamic library, framework or dylib, and the executable itself.&lt;br /&gt;
Each of these &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.dSYM&lt;/code&gt; bundle can contain binary Swift modules.&lt;/p&gt;

&lt;p&gt;In order for a Swift module to be picked up by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dsymutil&lt;/code&gt;, it needs to be registered with the linker. This registration occurs automatically for dynamic libraries and executables, but not for static archives. However, in many cases, Xcode handles this for you (not for custom build systems or custom build rules).&lt;/p&gt;

&lt;p&gt;We didn’t discover much about why Xcode sometimes fails to map these files; we suspect it might somehow relate to how we build the project through Tuist.io, but that’s just a guess for now.&lt;/p&gt;

&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;

&lt;p&gt;Since the issue is that Xcode (or the linker) can’t map the modules with the data types of the program’s source files (and frameworks), the only solution for now is the one proposed by swift-healthcheck.&lt;/p&gt;

&lt;p&gt;You can explicitly specify these modules for the Debug configuration using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-add-ast-path&lt;/code&gt; command passed to XLinker.&lt;/p&gt;

&lt;p&gt;(In brief, Xlinker is a command-line tool that allows developers to pass specific linker options directly when compiling applications by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-Xlinker&lt;/code&gt; followed by the desired option for fine control over linking.)&lt;/p&gt;

&lt;p&gt;We have a series of internal frameworks in our architecture depending on the service layer. To get this working, we need to repeat the process individually for each framewor by setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Other Linker Flags&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OTHER_LDFLAGS&lt;/code&gt;) of our main app target.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &quot;-Xlinker&quot;,
    &quot;-add_ast_path&quot;,
    &quot;-Xlinker&quot;,
    &quot;&apos;$(TARGET_BUILD_DIR)/\(frameworkName).framework/Modules/\(frameworkName).swiftmodule/$(NATIVE_ARCH_ACTUAL)-$(LLVM_TARGET_TRIPLE_VENDOR)-$(SHALLOW_BUNDLE_TRIPLE).swiftmodule&apos;&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frameworkName&lt;/code&gt; is the name of the framework.&lt;/p&gt;

&lt;p&gt;Since we’re using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tuist.io&lt;/code&gt; for creating project this looks like this:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;debugOtherLDFlags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forFrameworks&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;frameworks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]?)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;SettingValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;otherLdFlags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-ObjC&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// default flag&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;frameworks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherLdFlags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;astPathForFramework&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;SettingValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherLdFlags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;astPathForFramework&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;-Xlinker&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;-add_ast_path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;-Xlinker&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&apos;$(TARGET_BUILD_DIR)/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.framework/Modules/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.swiftmodule/$(NATIVE_ARCH_ACTUAL)-$(LLVM_TARGET_TRIPLE_VENDOR)-$(SHALLOW_BUNDLE_TRIPLE).swiftmodule&apos;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And boom, magically your debugger is back to working!&lt;/p&gt;

&lt;p&gt;This article wouldn’t have been possible without the help of the Immobiliare.it team (especially &lt;a href=&quot;https://github.com/stedurso&quot;&gt;@stedurso&lt;/a&gt;) and numerous online articles that guided us in finding the right solution.&lt;br /&gt;
As always, the best comes from teamwork.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The engineer you’d want to be</title>
   <link href="https://www.danielemargutti.com/2024/02/28/the-engineer-youd-want-to-be/"/>
   <updated>2024-02-28T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2024/02/28/the-engineer-youd-want-to-be</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG2.qdnI2u3rXdTFZykbwZaY.jpeg&quot; alt=&quot;&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Writing code is just one aspect that will make you a good engineer.&lt;br /&gt;
In a future where AI will be an integral part of every workflow, standing out in an increasingly crowded field will be important.&lt;/p&gt;

&lt;p&gt;Today, while scrolling through my newsletters, I spotted this news:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It turns out that Odysseus landed on the Moon without any altimetry data […]
The moon lander’s range finders were discovered to be inoperable a couple of hours before it was due to attempt to land on the Moon, so the company rewrote its software to take advantage of three telescopes on a NASA payload for altimetry purposes. (&lt;a href=&quot;https://actions.tldrnewsletter.com/web-version?ep=1&amp;amp;lc=95a7d39c-0d89-11ec-96e5-06b4694bee2a&amp;amp;p=8066c846-d60c-11ee-8fbb-051955a5e10d&amp;amp;pt=campaign&amp;amp;t=1709119906&amp;amp;s=6fe373e53628f3be19c4d07a48ed55e3cc5c9c7835a07ba4861fcdfa90b6001e&quot;&gt;TLDR&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Odysseus is the lander (developed by Intuitive Machines) that reopened the discussion about the Moon as a stable outpost after more than 50 years since the last Apollo mission.&lt;br /&gt;
Last Friday, the lander landed on the lunar surface, albeit not without issues.&lt;br /&gt;
Just a few hours after landing, IM discovered that the lander had inactive range finders (apparently missing a pencil-sized pin and a connector that allowed turning the laser on and off)&lt;/p&gt;

&lt;p&gt;Reading this captivating story, I found myself reflecting on the countless occasions when, addressing challenges with my team, I’ve jokingly remarked, &lt;em&gt;“Well, it’s not like we’re sending rockets to the moon, right?”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Indeed, it’s true.&lt;br /&gt;
&lt;em&gt;Most of the time, “good enough” suffices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Many developers often content themselves with slapping on the first patch they find, convinced that the surrounding environment (high-performance hardware, user use cases, etc.) will compensate for deficiencies.&lt;/p&gt;

&lt;p&gt;Many of them end up labeling bigger problems with a nice “refactor” tag.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It needs rewriting.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Too hard to understand, poorly written, incomprehensible, no documentation.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;It’s better to start over.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I know because I did it myself for a long time.&lt;br /&gt;
It’s easier, it’s just more fun.
&lt;em&gt;Let’s rewrite everything!&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-world-were-heading-towards&quot;&gt;The world we’re heading towards&lt;/h3&gt;

&lt;p&gt;However, the world we’re heading towards, on one hand, is creating a large audience of developers capable of producing something “good enough” even with the help of AI, and on the other hand, &lt;strong&gt;it demands from developers skills that go beyond the latest shiny framework of the moment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Companies have never sought ninja developers, just as they won’t seek proficient prompters to indoctrinate AI. What they’re looking for instead are professionals they can rely on.&lt;/p&gt;

&lt;p&gt;If there’s a problem, no manager wants to hear: &lt;em&gt;“Let’s rewrite everything from scratch in the newest framework x instead of y, so we won’t have that problem anymore”&lt;/em&gt; .&lt;br /&gt;
&lt;strong&gt;Why? Most of the time solves a known problem only to add new ones that are still unknown.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is expected instead is the responsiveness to request the appropriate time to deeply analyze and propose solutions (and perhaps those solutions will end up being a rewrite, but they’ll be so while explicitly stating real reasons, not assumptions).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Being able to read and analyze others’ code is crucial, even more so than being able to write it.&lt;/strong&gt;&lt;br /&gt;
Unless you are the only programmer on Earth.&lt;/p&gt;

&lt;p&gt;Can you picture if, when faced with a complex problem like the one with Odysseyum, Intuitive Machine’s engineers had just thrown up their hands and said:&lt;br /&gt;
&lt;em&gt;“Ah well, let’s start from scratch the next time”?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;As a result, the company scrambled to rewrite its software to take advantage of three telescopes on a NASA payload, the Navigation Doppler Lidar for Precise Velocity and Range Sensing, for altimetry purposes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Being adaptable, responsive, and analytical makes a tech person more than just a code writer.&lt;br /&gt;
Digging deep into topics and issues is what will really make you stand out in a growing crowd.&lt;/p&gt;

&lt;h3 id=&quot;links&quot;&gt;Links&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;This story &lt;a href=&quot;https://danielemargutti.medium.com/the-engineer-youd-want-to-be-b12f49454bd0&quot;&gt;was also published on Medium&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;ArsTechnica on &lt;a href=&quot;https://arstechnica.com/space/2024/02/it-turns-out-that-odysseus-landed-on-the-moon-without-any-altimetry-data/?utm_source=tldrnewsletter&quot;&gt;Odysseus story&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Don&apos;t hire for passion</title>
   <link href="https://www.danielemargutti.com/2024/01/28/dont-hire-for-passion/"/>
   <updated>2024-01-28T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2024/01/28/dont-hire-for-passion</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG3.lduZ_WvkEsvCyKRLIFAD.jpeg&quot; alt=&quot;&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let me to be honest, there is a big lie in the world:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Do what you love and you’ll never work a day in your life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’re reading this post and you know me, you’re probably wondering if I’ve lost my mind or something. I joined the world of computer science driven by a strong passion.&lt;/p&gt;

&lt;p&gt;Yet, many years of technical interviews with dozens and dozens of people of all seniorities have left me with a bitter realization.&lt;br /&gt;
You really should try to avoid making assumptions based on how passionate the person in front of you appears to be.&lt;br /&gt;
&lt;strong&gt;You don’t want to hire passionate people.&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;You want to hire professional people.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yeah, I get it. Passionate folks often have &lt;em&gt;extra drive&lt;/em&gt;, maybe even find the best or most efficient solution (unless they get stuck in their own loop).&lt;br /&gt;
But let’s face it, relying on their reliability can be iffy.&lt;/p&gt;

&lt;p&gt;But why?
Passion is, by definition, &lt;em&gt;illogical&lt;/em&gt;.&lt;br /&gt;
It often leads people to act without thinking - we call them &lt;em&gt;crimes of passion&lt;/em&gt; for a right reason.&lt;br /&gt;
People lead by passion are generally poorly accountable in most of the situations.&lt;/p&gt;

&lt;p&gt;Mostly, though, the distinction here is that the professional will do the parts of the job they dislike just as they will the parts they like - &lt;strong&gt;the professional knows it’s a job, not a life choice or an identity&lt;/strong&gt;. You can’t say the same for passionate ones.&lt;/p&gt;

&lt;p&gt;Most of the time, if these individuals can’t manage themselves, they need to be fed with new challenges. Sometimes these tasks end up being created ad hoc without a real need. &lt;strong&gt;It’s equally true that once any resource is depleted, they’ll be the first to leave to plunder another team.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, unless you’re developing the next rocket to Mars or you’re absolutely sure that person can feed their ego outside the team, my advice is to move on.&lt;/p&gt;

&lt;p&gt;If you are building a team or you’re a passionate developer take a look at the link below and read it carefully.&lt;/p&gt;

&lt;h3 id=&quot;links&quot;&gt;Links&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://hbr.org/2023/05/dont-let-passion-lead-to-burnout-on-your-team&quot;&gt;Don’t Let Passion Lead to Burnout on Your Team&lt;/a&gt; - Harvard Business Review&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Beyond specialization</title>
   <link href="https://www.danielemargutti.com/2023/08/10/beyond-specialization/"/>
   <updated>2023-08-10T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2023/08/10/beyond-specialization</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG1.lwirApISXm79E8IOA5v6.jpeg&quot; alt=&quot;image&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I dove into programming at a young age, driven by boundless curiosity.&lt;br /&gt;
It was a world where anything was possible, and that very curiosity became my lifelong passion, eventually evolving into my career.&lt;/p&gt;

&lt;p&gt;The fact that it also happened to be a pretty cool job in these years was just a lucky coincidence. &lt;br /&gt;
&lt;em&gt;If I’d been into poetry, I might be under a bridge right now, scribbling away!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anyway, for a long time, I lived in a &lt;strong&gt;world that strongly encouraged specialization as a career path&lt;/strong&gt;. The fact that many schools, especially at higher levels, emphasize strong specialization represents the epitome of this way of thinking.&lt;/p&gt;

&lt;p&gt;The term &lt;em&gt;&lt;a href=&quot;https://www.quora.com/What-is-‘ninja’-in-ninja-web-developer-What-does-he-she-do-What-kind-of-programming-knowledge-has-he-she&quot;&gt;ninja developer&lt;/a&gt;&lt;/em&gt;, which was quite popular a few years ago (now mostly used with a negative connotation), perfectly encapsulates this perspective.To summarize this thought, hyper-specialization was once seen as the only way to pick the high-hanging fruit in fields where the low branches are bare.Moreover specialization feels like a more predictable and measurable path for a tech career.&lt;/p&gt;

&lt;p&gt;Unfortunately, as the world of software has become more complex and diverse in terms of skills and professions, being highly specialized doesn’t always pay off.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;While it’s true that a highly specialized team can push the limits in each field, in most companies, this isn’t strictly necessary.&lt;/strong&gt; &lt;br /&gt;
What truly matters is how diverse professions can seamlessly interact, mutually influence, and comprehend one another effectively.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recently at my company we’ve been recently trying out small project teams (a.k.a. pods) with measurable business goals and time constraints.These teams often have a mix of professionals like designers, frontend/backend developers, and product owners.&lt;/p&gt;

&lt;p&gt;After a few tries, some more successful than others, we came to appreciate how essential it was to find the perfect mix of personalities for our team.Typically, teams consisting of individuals with hybrid skill sets were more adept at cultivating empathy and understanding among their members.&lt;/p&gt;

&lt;h2 id=&quot;why-we-need-hybrid-people&quot;&gt;Why we need hybrid people?&lt;/h2&gt;

&lt;p&gt;The world needs more hybrid people because the world is getting more complex.While specialists are important because they help us push the limits in each field, we also need people who can see the big picture and guide the team efforts.&lt;/p&gt;

&lt;p&gt;Having a wide base of skills with one or two specialties gives you more tools in your toolbox — more ways and points of views to solve problems effectively.&lt;/p&gt;

&lt;p&gt;You can think of these individuals as the alloys of various materials:&lt;/p&gt;

&lt;p&gt;These constituent materials have notably dissimilar chemical or physical properties and are merged to create a material with properties unlike the individual elements.— wikipedia&lt;/p&gt;

&lt;p&gt;Embracing hybrid skills enables you to excel beyond the sum of your individual capabilities and hones your empathy in comprehending and embracing diverse viewpoints.&lt;/p&gt;

&lt;p&gt;Returning to our experiment, I observed how [sometimes] highly specialized team members with lower empathy skills can be sources of friction within the whole team. This resulted in a negative overall perception of the work and, consequently, less favorable outcomes (even though, theoretically, we had higher technical skills).&lt;/p&gt;

&lt;h2 id=&quot;to-sum-it-up&quot;&gt;To sum it up&lt;/h2&gt;

&lt;p&gt;In the end, my suggestion is to explore areas as distant as possible from your own expertise, while sharpening your empathy and understanding.&lt;/p&gt;

&lt;p&gt;You might not always need to perform an Apollo 13-style astronaut rescue, but you’ll frequently encounter situations that feel light-years away from your usual work. Mastering these situations with finesse will make you a more well-rounded and valuable professional in countless settings.&lt;/p&gt;

&lt;p&gt;If you had a blast reading this, why not hop on board our newsletter? You’ll get all the latest posts delivered right to your inbox. No spam. Seriously, we pinky promise!&lt;/p&gt;

&lt;h2 id=&quot;your-thoughts&quot;&gt;Your thoughts&lt;/h2&gt;

&lt;p&gt;Do you think hybridizing could supercharge your career, or is specialization your secret sauce for job satisfaction? Share your insights; drop a comment below!&lt;/p&gt;

&lt;h3 id=&quot;literatures&quot;&gt;Literatures&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/u-o-shaped-employees-lampros-lamprou/&quot;&gt;Technical literature defines these types of individuals&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;An interesting read on the topic &lt;a href=&quot;https://www.amazon.com/Range-Generalists-Triumph-Specialized-World/dp/0735214484&quot;&gt;“Range: Why Generalists Triumph in a Specialized”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Task &amp; Threads in Swift Concurrency</title>
   <link href="https://www.danielemargutti.com/2023/08/05/task-threads-swift-concurrency/"/>
   <updated>2023-08-05T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2023/08/05/task-threads-swift-concurrency</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG4.j9z5DQKB1x5.J40Ha4Id.jpeg&quot; alt=&quot;&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To understand the difference between tasks and threads, we need to take a look at what threads are and how they are used in a modern general-purpose computer.&lt;/p&gt;

&lt;p&gt;Since this is not a post about CPU architectures I’ll try to simplify some concepts.&lt;/p&gt;

&lt;p&gt;At the very low level every processor has a thing called registers.We can refer to registers as a type of computer memory built directly into the processor that is used to store and manipulate data during the execution of a program instructions.&lt;/p&gt;

&lt;h3 id=&quot;cpu-registers&quot;&gt;CPU Registers&lt;/h3&gt;

&lt;p&gt;A register is just like container for a variable; modern processors uses 64-bit registers, which means a single unit can store 64 bits of data (8 bytes).&lt;/p&gt;

&lt;p&gt;When a CPU executes a program it loads data from RAM into register, does operations and store them back to the memory.&lt;/p&gt;

&lt;p&gt;A modern CPU has multiple cores, each with one set of registers including a program counter. Some CPUs have two sets of registers per core for faster thread switching (we call it hyper-threading).For sake of simplicity a core is an entire CPU  that just happens to be attached to the first one for faster communication.There are different types of registers: unfortunately while we’re allowed to have a large amount of local variables, there are a limited amount of registers into a CPU.To handle this issue there is a region of the memory (RAM) used to store local variables that aren’t currently in registers.&lt;/p&gt;

&lt;p&gt;This region is called Stack: each time you call a function its variables get added to the top of the list; once a function body is finished their variables are taken off the top (the concept of a stack).&lt;/p&gt;

&lt;h3 id=&quot;threads&quot;&gt;Threads&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Threads are a sequence of execution of code which can be executed independently of one another. You can consider it as the smallest unit of operations that can be executing by an operating system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the very low level a thread is represented as a snapshot of the CPU, specifically the state of all the registers, the content of the stack and few other stuff used by the kernel to keep track of the thread.&lt;/p&gt;

&lt;p&gt;Modern CPUs runs multi-tasking OSs which allows to switch which thread is running at frequent intervals allowing the concurrency happens.Each thread is executed for a limited amount of time, then a context switch happens and so on (in a multi-core environment, concurrency can be achieved via parallelism in which multiple tasks are executed simultaneously if they are independent each others).&lt;/p&gt;

&lt;p&gt;Context switching can be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Voluntary: the thread has completed its work and reports it to the kernel” (cooperative multitasking).&lt;/li&gt;
  &lt;li&gt;Non-Voluntary: the scheduled time for the thread has ended for now, and execution is temporarily suspended by the kernel (preemptively multitasking).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preemptive multitasking allows for better resource management and prevents poorly-behaved programs from taking full control of the system (more on differences).&lt;/p&gt;

&lt;h3 id=&quot;the-hidden-cost-of-threads&quot;&gt;The hidden cost of threads&lt;/h3&gt;

&lt;p&gt;The context switching doesn’t come for free; in fact, it has a cost.When the OSs suspend a thread it must save all the registers into the RAM, then load the state of the incoming thread previously saved on RAM.&lt;/p&gt;

&lt;p&gt;The load/unload operations of threads take time and memory. Moreover, the kernel needs to keep track of these threads to resume or suspend them, which means additional memory usage.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: Keep in mind that significant progress has been made in processor and operating system architectures. Today, a thread can share various state information with other threads, reducing overhead. Most processors, especially multi-core processors and GPUs (graphics processing units), now incorporate hardware that makes running multiple threads particularly efficient.Nevertheless, it’s important to consider that thread models may not be well-suited for all computer architectures, and this remains an optimization problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;swifts-task&quot;&gt;Swift’s Task&lt;/h3&gt;

&lt;p&gt;The new Swift Concurrency Model uses an hybrid approach: it has a lightweight thread-like object called Task (in other languages they call it coroutines or fibers or, simply, program threads - vs kernel threads).OS’s Kernel know nothing about these objects. It’s fully managed by the internal Swift’s concurrency library. You can consider it a new abstraction layer over the OS.&lt;/p&gt;

&lt;p&gt;The Concurrency Library does its own cooperative multitasking to decide which tasks needs to be mapped to real threads. Every time we’re using the await statement, we’re telling to the library it’s someone els’s turn, giving up your actual thread.&lt;/p&gt;

&lt;p&gt;This model is called &lt;a href=&quot;https://en.wikipedia.org/wiki/Thread_(computing)#M:N_(hybrid_threading)&quot;&gt;M:N Threading Model&lt;/a&gt; or Hybrid Threading (there are 3 different types of threading models).&lt;/p&gt;

&lt;p&gt;This a model which maps M user threads onto N kernel threads.This enables a large number (M) of user threads to be created, due to their light weight, which still allowing (N-way) parallelism.Many other languages uses this model to create lightweight threads.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The advantage over using one thread for each task (kernel only threading) is that you consume less resources, like memory (both virtual and physical) and kernel objects. You also get less context switches, which increases performance (in the ideal case, where you have as many running threads as you have processors, you may have almost no context switches).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The advantage over user only threading is that you can take advantage of multiple CPUs or multiple CPU cores. And if one task blocks, you can create another kernel thread to use the available CPU more efficiently.&lt;/p&gt;

&lt;p&gt;A disadvantage over kernel only scheduling is possibly bigger latency: if all the threads in the pool are busy and you add new short task, you may wait a long time before it starts executing.&lt;/p&gt;

&lt;p&gt;In the best case scenario that what previously would have required many many and expensive real threads, each running for a short period of time, now requires only a tiny number of real threads.&lt;/p&gt;

&lt;p&gt;Moreover they all run for as long as the kernel will let them, minimizing both memory overhead and therefore the switching cost.&lt;/p&gt;

&lt;h3 id=&quot;threads-explosion&quot;&gt;Threads Explosion&lt;/h3&gt;

&lt;p&gt;Since this topic is somewhat off-topic, I will briefly mention the concept of thread explosion, leaving links to two articles that delve into the issue at the end.&lt;/p&gt;

&lt;p&gt;As we said context switch has a performance cost. When this happens a lot (you create manu more threads compared to the number of available CPU cores) the context switching grows high: this event is called threads explosion.&lt;/p&gt;

&lt;p&gt;This lead to some issues like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Memory overhead: each blocked thread is holding onto valuable memory and resources while waiting to run again.&lt;/li&gt;
  &lt;li&gt;Scheduling overhead - as new threads are brought up, the CPU need to perform a full thread context switch in order to switch away from the old thread to start executing the new thread. With limited cores and a lot of threads, the scheduling latencies of these threads outweigh the amount of useful work they would do, therefore, resulting in the CPU running less efficiently as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While Swift Concurrency is doing a pretty good job of preventing thread explosion, we cannot deny the fact that it will cause a very significant bottleneck in some cases.If you want to know more about this topic you can watch the WWDC21 Session “Behind the scenes” and read this interesting article by Senpai “Swift Concurrency vs Thread Explosion”.&lt;/p&gt;

&lt;h4 id=&quot;literatures&quot;&gt;Literatures&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.javatpoint.com/preemptive-vs-cooperative-multitasking#:~:text=Preemptive%20multitasking%20forces%20apps%20to,all%20of%20the%20processor%20resources.&quot;&gt;“Differences between Preemptive and Cooperative Multitasking”&lt;/a&gt; by JavaPoint&lt;/li&gt;
  &lt;li&gt;An interesting article about threading models &lt;a href=&quot;https://medium.com/swlh/different-threading-models-why-i-feel-goroutine-is-better-though-with-some-limitations-b73863ba4dae&quot;&gt;“Threading Models”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;As fair I know it should be used by Go (with goroutines), Erlang (with processes) but also by C++, Java and Python. In fact Go and Erlang go further with another layer called &lt;a href=&quot;https://www.reddit.com/r/ProgrammingLanguages/comments/6mm4v1/what_are_the_disadvantages_of_an_mn_threading/dk2mrk9/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&quot;&gt;O:M:N thread model&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>The effect of indirect actions on team dynamics</title>
   <link href="https://www.danielemargutti.com/2023/04/10/the-effect-of-indirect-actions-on-team-dynamics/"/>
   <updated>2023-04-10T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2023/04/10/the-effect-of-indirect-actions-on-team-dynamics</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG3.i7w1IkMfNTKYlrEddHFq.jpeg&quot; alt=&quot;&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When I started this role about 4+ years ago, I never thought about how indirect actions could shape the people around me even more than any direct action or speech on the stage.&lt;br /&gt;
This is true both in the short and long term.&lt;/p&gt;

&lt;p&gt;Some time ago, during a break, we discussed this pattern along with some colleagues. It’s impressive to see how people slowly start to imitate their managers in their everyday work life, both in positive and negative aspects.&lt;/p&gt;

&lt;p&gt;Looking at everyday life, it’s easy to recognize how the mood of those around us very influences us. Usually, it’s not even something we do consciously; most of the time we unconsciously pick up on a different tone of voice, observe the body language of people nearby, and our brain does the rest.&lt;/p&gt;

&lt;p&gt;Nothing strange; in fact, our brain is hard-wired for this stuff.We are constantly on the lookout for threats in our environment that could lead to bad news. Our brain assembles signals from gestures, voice tone, facial expression, words, and so on to infer behavior or make (sometimes wrong) assumptions.&lt;/p&gt;

&lt;p&gt;Moreover, humans tend to mirror each other.Mirroring is a nonverbal technique where a person copies another person’s body language, attitude, or vocal qualities.From an evolutionary perspective, being in sync with members of your group is vital to survival; it signals that we are connected to a person in some way. The whole point of mirroring is that it’s a way to understand better and connect with others.Being able to mirror someone is the same as listening to someone.&lt;/p&gt;

&lt;h3 id=&quot;how-does-this-affect-your-role&quot;&gt;How does this affect your role?&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Spreading fever is not a good idea, even if there are reasons to feel sick.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Mirroring&quot;&gt;Mirroring in teams is a sign of trust&lt;/a&gt;, but you must take it responsibly.How often have you left a bad meeting only to have those strange vibes picked up by other people?&lt;/p&gt;

&lt;p&gt;I consider myself a very empathetic person.It’s easy for me to pick up on the general mood of a person or group in the room. For the same reason, it has always been easy for me to influence (and be influenced by) the “temperature” of people.&lt;/p&gt;

&lt;p&gt;However, in any leadership role (and generally speaking, every senior role) part of the job is to learn when and how to intentionally change the vibes in the room.Sometimes it’s not spreading flu, but just a rash.Some other times instead, you need to take action to avoid worse situations.&lt;/p&gt;

&lt;p&gt;It’s not always easy, that’s for sure.You will end up making many more mistakes than you would like.But it’s an exercise that you carry with you throughout your entire life.&lt;/p&gt;

&lt;p&gt;I would love to take a look at some tricks you can apply to reset the temperature of a group when a flu is about to spread all over the members.&lt;/p&gt;

&lt;h3 id=&quot;reset-the-temperature&quot;&gt;Reset the temperature&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Model the environment using your tone, body language, and wise word choice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’re noticing a major shift in someone’s demeanor, instead of guessing what’s going on for them, it is better to ask an open question about what they need or how they’re feeling.&lt;/p&gt;

&lt;p&gt;Be intentional about the tone that you’re using since your body language always reflects your real mood. You’re responsible for communicating that you want to hear what they have to say, and that you’re here to support them.&lt;/p&gt;

&lt;p&gt;Soft eye contact is better than keeping constant eye contact (which is, frankly, a little creepy). You can break eye contact every few seconds naturally, then connect again, and this still feels attentive and affirming to the other person.&lt;/p&gt;

&lt;p&gt;You smiled a bit, told a little joke that made them chuckle, and nodded at the pace that they spoke to indicate you were listening, and their mood started to change.Sometimes people may feel overwhelmed, stressed, or distracted. In these situations, the best way you can do is to take a break.It’s like when you feel stuck with a coding issue.That’s the same, take a breath… and a break.Offer a pause in the conversation and a plan to return to it later.Try to intentionally avoid putting someone else on the spot or making them feel attacked:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“I really want to support you on this.How would you feel about us taking a break now to spend some more time thinking it through?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;what-i-learned&quot;&gt;What I learned&lt;/h3&gt;

&lt;p&gt;If you aim to be in a leadership role, you’re a senior engineer or you’re in charge of a team, you should always remember how strongly indirect actions can influence all the members of your group.Moreover, it’s your responsibility to avoid acting like a flu spreader.You need to acknowledge tense or awkward situations, or you’re going to risk developing a forever-antagonistic relationship with them.Also not supported assumptions can lead you to the wrong path: talk to the people.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Not everything has to be perfect the first time</title>
   <link href="https://www.danielemargutti.com/2022/08/04/love-the-imperfection/"/>
   <updated>2022-08-04T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2022/08/04/love-the-imperfection</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG1.3Ol5Ufu5j23jC61.est0.jpeg&quot; alt=&quot;&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s strange, but it often happens to many senior people: &lt;strong&gt;the more you move towards your career, the more it’s hard to love imperfection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each new project starts with constraints: some of them are related to time-to-market bounds, some others instead came from the necessity to optimize and delay the necessary resources (mostly development time) while evaluating user feedback.&lt;/p&gt;

&lt;p&gt;Constraints mean that we have to pick things that will get as much attention as we would ideally like. The results are removed features, less-than-ideal technical approaches, troubles for some teams, and so on.&lt;/p&gt;

&lt;h2 id=&quot;engineers-and-the-idea-of-perfection&quot;&gt;Engineers and the idea of perfection&lt;/h2&gt;

&lt;p&gt;It’s hard not to want everything to be perfect, and it’s harder to convince people about what’s behind these constraints.&lt;/p&gt;

&lt;p&gt;This is where I’ve often encountered great engineers, product managers, and designers getting lost.&lt;/p&gt;

&lt;p&gt;But at this point, I must confess: I damn hate the MVP term.
MVP is the acronym for “Minimum Viable Product”.
Even with all the best intentions, it’s just a game of diminishing returns:
“minimum” stands for “the least effort“; “viable” is another low bar meaning something isn’t often desirable.&lt;/p&gt;

&lt;p&gt;Definitely, it’s far from being something someone can be excited or nevertheless proud of.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Communication is essential: words matter.&lt;/strong&gt;&lt;br /&gt;
(Especially when you’re talking to a tech team)&lt;br /&gt;
MVP is often considered a slap in any tech people’s face; less than ideal, the symbol of “imperfection”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most engineers refuse the idea of imperfection.&lt;br /&gt;
The first message you should pass is to get the team comfortable with the uncertainty of software development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time delays, requirements, and goals changes; depending on the area, everyone can feel the volatility of the development process of a new feature on their skin.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;not-everything-has-to-be-perfect-the-first-time&quot;&gt;Not everything has to be perfect the first time&lt;/h2&gt;

&lt;p&gt;Explaining the reasons behind choices is fundamental to align the product and tech team better. It’s not about high-fidelity mockups; it’s more about sharing measurable goals behind the idea.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Knowing what truly has to be perfect can help focus limited resources on the right spot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then: not everything has to be perfect the first time.&lt;/p&gt;

&lt;p&gt;Communicating your goals with a detailed long-term roadmap is a typical error.&lt;br /&gt;
The far future is unknown, at best.&lt;br /&gt;
It will constantly change as you move forward: reduce the detail in your plans as they get farther ahead avoid overthinking.&lt;/p&gt;

&lt;p&gt;As I said at the beginning of this post, it’s hard to love imperfection.&lt;br /&gt;
Most of the time, the response to “we can fix it later” is something in between melancholy and sad: “we probably won’t”.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Teams are asked to compromise daily; promises of “we’ll fix it later” sound really hollow if you, as manager, don’t create a structured workflow with enough space to fix and optimize things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Developing any digital product is stressful for both product and tech teams. Both will experience the pain of removing features, changing priorities, and reducing/expanding time daily.&lt;/p&gt;

&lt;p&gt;As a manager is critical to focus on better goal settings &amp;amp; communication: what’s important, what’s not, what’s the reason behind a choice.&lt;/p&gt;

&lt;p&gt;As an engineer is essential to feel comfortable with the ever-present uncertainty of making digital products.
Resources are limited: reduce the scope, be crafty, focused, and precise.&lt;br /&gt;
You will never get perfection in a constantly changing world, and no one needs them.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Thoughts on moving to a leadership role</title>
   <link href="https://www.danielemargutti.com/2022/06/15/thoughts-on-moving-to-a-leadership-role/"/>
   <updated>2022-06-15T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2022/06/15/thoughts-on-moving-to-a-leadership-role</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG4.oGL_q9SuufWwRaQzPvGr.jpeg&quot; alt=&quot;&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Moving to a leadership role does not mean you will need to check every line of each PR, tearing your hair and hoping it will be not that bad day.&lt;/p&gt;

&lt;p&gt;When I started the role of Technical Lead (feel free to replace it with any other variation of the role) I had a strong craving to control everything around me. This is not anything strange for tech people new to this kind of role.&lt;/p&gt;

&lt;p&gt;Therefore it’s easy to feel overwhelmed, sad, or lost at times. This already happens in the early stages, when your team is small and the concurrent tasks are still manageable.&lt;br /&gt;
An example of this behavior is the attempt to perform every code review.&lt;br /&gt;
Probably you’re concerned that something will break if you don’t pay the necessary focus.&lt;br /&gt;
You won’t say anything new but, listen to me, it isn’t feasible and it does not scale.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But what you can do instead?&lt;/em&gt;&lt;br /&gt;
Some people hates code reviews but they’re an awesome opportunity to explore how someone solved a problem in their unique way and to have discussions on the programming craft.&lt;/p&gt;

&lt;p&gt;Before anything else…&lt;br /&gt;
Before any automated tools, before linters and formatters you need to focus on two fundamentals activities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Teach your team to review effectively&lt;/strong&gt; Emphasize the scope of a review the kindness, clarity and throughness.
You can’t write and review all the code for your team, neither you can hire for people for this job. Put your team in position to handle them effectively.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Establish Paradigms&lt;/strong&gt; Setting a few paradigms and rules during product development will save your life.
Once you’ve set clear boundaries, reviews become laser-focused. Reviewers can focus on the specific features and they don’t get distracted by accessory elements. A shared structure is one of the best things to invest in; others can leverage and build on top of it.  Define how different parts must communicate, the overall architecture, and general approach to UI development leaving the opportunity to evolve and change it over time (gradually).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have consolidated these changes you can build at the top of it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Document processes&lt;/strong&gt; Team members should be aware of the scope and structure of each PR.  Using PR templates allows people to correctly explain what have they done and offer a clear overview to any reviewer.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integrate Automated Tools&lt;/strong&gt; Linters, formatters &amp;amp; automated tests release people from the burdens of the boring parts of a review (yeah, I know, some people are human linters but, okay). Strengthen your release pipelines with tests, monitoring, and rollback.
This will help to prevent, detect and mitigate defects.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Healthy approach to code reviews</title>
   <link href="https://www.danielemargutti.com/2022/04/22/healthy-approach-to-code-reviews/"/>
   <updated>2022-04-22T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2022/04/22/healthy-approach-to-code-reviews</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/images/OIG3.htZG5evenzUxIyK_rjks.jpeg&quot; alt=&quot;&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Code reviews are weird monsters.
With no doubts they improve the overall quality of the code and help programmers build relationships and work together more effectively.&lt;/p&gt;

&lt;p&gt;However asking for a code review puts many people on edge because it is just like laying your creative soul bare. By generally speaking most of the devs lives CRs as a &lt;strong&gt;“personal intrusion”&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Your team is only good as your weakest reviewer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are some tips I’m collecting about it in these years.&lt;/p&gt;

&lt;h2 id=&quot;who&quot;&gt;Who?&lt;/h2&gt;

&lt;p&gt;Code Review is a team activity. A good mixture of senior and junior members aim to create the right environment for learning: senior members can battle test their code related to APIs clarity, junior devs have a chance to learn new things.&lt;/p&gt;

&lt;p&gt;Depending your team size and structure each review may require one or more engineering approval to be merged.
From my experience if your team is pretty small (less than 5 people) you can stick with 2 reviewers to keep a good balance on sharing knowledge.&lt;/p&gt;

&lt;p&gt;If you are growing over 8+ (without moving to cross-functional teams) you should change your approach: your CR should require at least one engineer and you should start moving the team to a more static organization where part of the program are assigned to an ownership which is also responsible for manteniance and evolution of that code (more specialized skills, less shared knowledge with a modular architecture which follow a shared vision – we’ll look at that in one of the upcoming posts).&lt;/p&gt;

&lt;p&gt;Depending of the affected part you may decide to assign it to more people; I’ve seen it vary, for core layers you may considering sharing the knowledge across the entire team.&lt;/p&gt;

&lt;h2 id=&quot;help-me-help-you&quot;&gt;Help me, help you&lt;/h2&gt;

&lt;p&gt;We don’t have hard requirements for adding descriptions to pull requests but recently I found it very useful and instructive to use Templates.
It help you to create a good habit both for the author and any reviewer.&lt;/p&gt;

&lt;p&gt;First of all the author is allowed to take a deep breath and focus on what he did, describing the idea, the implementation and force himself to take an overview look to the PR.&lt;/p&gt;

&lt;p&gt;That said, anyone who is reviewing code will need to figure out what is changing and why it’s changing.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;In general, we think it’s good to consider what people may or may not know about your PR, and aim to give them context so that they can help you.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;small-prs-is-not-a-matter-of-loc&quot;&gt;Small PRs is not a matter of LoC&lt;/h2&gt;

&lt;p&gt;I strive to build things in small units; when planning a new milestone my approach is the old divide et impera. I want to break our code down as much as possible and submit small, digestible PRs.
By doing this, the team can review quicker and move faster.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;However, when you think about a small PR you often refer in terms of lines of code (LoC).&lt;/strong&gt;
&lt;strong&gt;Instead you should think in terms of conceptual changes.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, a variable name refactor maybe a big review because it may impacts lots of files in your code base. However it still small because it’s just a single concept (the renaming).&lt;/p&gt;

&lt;p&gt;In my engineering we values and encourages the combination of small PRs and quick reviews.&lt;/p&gt;

&lt;h2 id=&quot;author-pov&quot;&gt;Author POV&lt;/h2&gt;

&lt;p&gt;As author of a merge request is your responsibility to avoid waste of time &amp;amp; energy of your collegues.&lt;/p&gt;

&lt;p&gt;CR must be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Highly scoped and limited&lt;/strong&gt;: Changes should have a narrow, well-defined and self-contained scope. If it takes more than one hour think about splitting it.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Correct&lt;/strong&gt;: It must handle the problem and should be performant enough for its use case; main edge cases must be handled correctly and tested.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Readable&lt;/strong&gt;: Reduce the cognitive load necessary for an user to be productive with your code (it includes BL, naming &amp;amp; organization of the classes, functions and variables).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Elegant&lt;/strong&gt;: Ask yourself “would you be proud and excited to work with this code?” As maintainer of the program you must leave the codebase better than what it was before.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Huge refactoring is a separate activity&lt;/strong&gt; If you are planning to make a refactoring which touches many parts of the app consider it moving in another CR. Unintended behavior changes can leak into the code base without anyone noticing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;reviewer-pov&quot;&gt;Reviewer POV&lt;/h2&gt;

&lt;p&gt;Your work as reviewer is only partially related to the tech side; you should put yourself into the correct mindset when approaching a new merge request.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Be nice&lt;/strong&gt;: Always assume the best intentions: everyone wrote questionable code before, it happened, and it will happen again. Be kind and avoid downplaying words by using easily, simply or just… It just don’t serves no purpose.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Point out the good things&lt;/strong&gt;: Don’t forget to praise concise/readable/efficient/elegant code. If you learned something new or interesting while reviewing let it the author know.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Take the right time&lt;/strong&gt;: Truly understand the task and the code used to achieve it; once you are confident start writing your thoughts. Consider splitting long review sessions if it takes more than one hour (attention to details tend to drop easily).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ask &amp;amp; Provide Context&lt;/strong&gt;: If you see something you don’t know about you should ask for details; always provide alternatives, we could make it betterdoes not make any sense.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-you-should-check-in-a-code-review&quot;&gt;What you should check in a Code Review&lt;/h2&gt;

&lt;p&gt;When you are doing a CR you should focus to the following list of activities:&lt;/p&gt;

&lt;h3 id=&quot;purpose&quot;&gt;Purpose&lt;/h3&gt;
&lt;p&gt;The reason a code exists is to satisfy one or more business requirements.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Does the code you received achieve all the requirements?&lt;/li&gt;
  &lt;li&gt;Does it well support edge cases?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;
&lt;p&gt;Think carefully about how you would have solved the same problem.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If it’s different, why is that? Does your implementation handle more edge cases?&lt;/li&gt;
  &lt;li&gt;Is it shorter/easier/cleaner/faster/safer (yet functionally equivalent)?&lt;/li&gt;
  &lt;li&gt;Do you see potential for useful/not-over-enginnering abstractions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;clarity&quot;&gt;Clarity&lt;/h3&gt;

&lt;p&gt;When possible code must require a low cognitive load to be understood. Over-engineering is a particular type of complexity where developers have made the code more generic than it needs to be, or added functionality that isn’t presently needed by the system.&lt;/p&gt;

&lt;p&gt;As reviewer you should be especially vigilant about over-engineering to limiting &lt;strong&gt;future speculation&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;naming--conventions&quot;&gt;Naming &amp;amp; Conventions&lt;/h3&gt;

&lt;p&gt;Naming and conventions are tools to reduce cognitive load. As team you should create, maintain and update your list of conventions; this set of rules does not strictly depend by technologies but also by the single personality of the team members.&lt;/p&gt;

&lt;p&gt;By generally speaking you should keep in mind the following questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Are variables/classes/functions clear in their intentions?&lt;/strong&gt;: You should be able to grasp the concepts and the flow in a reasonable amount of time.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Does the code follows your team code style?&lt;/strong&gt;: Code should consistent with the rest of the project in terms of style, API conventions etc. Deviations could be accepted but must be discussed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Are all comments into the code necessary?&lt;/strong&gt;: Redundant and unnecessary comments clutter the code. Usually comments should explain why some code exists and rarely what is doing. If the code isn’t clear enough to explain itself, then there is room to make it simpler.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Handle TODOs&lt;/strong&gt;: TODOs just pile up in code, and tends to become stale over time. You should be vigilant about their presence.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tests--docs&quot;&gt;Tests &amp;amp; Docs&lt;/h3&gt;

&lt;p&gt;If your team maintain a test suits, as reviewer always ask for unit, integration, or end-to-end tests as appropriate for the change. Tests should be part of the code review unless author is handling an emergency.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Does the test cover interesting cases?&lt;/strong&gt; Truly untestable features are rare, but untested implementations are too common.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Are tests readable?&lt;/strong&gt; You should be able to understand what a test do.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Does this CR break backward compatibility?&lt;/strong&gt; Think carefully existing production code and check if new code can break compatibility somewhere.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Was the external documentation updated?&lt;/strong&gt; Outdated documentation is worse than none.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;

&lt;p&gt;Keep in mind: code review is an asynchrnous activity don’t bother your reviewers with real-time communication unless you can’t come to an agreement or you think it’s necessary to the complexity of the changes.&lt;/p&gt;

&lt;p&gt;Internet is full of articles about this topic; the links below are a short list of further readings where other details are discussed.&lt;/p&gt;

&lt;h4 id=&quot;links&quot;&gt;Links&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/joho/awesome-code-review&quot;&gt;Awesome Code Review&lt;/a&gt;: A curated list of tools, articles, books, and any other resource related to code review&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/palantir/code-review-best-practices-19e02780015f&quot;&gt;Code Review Best Practices&lt;/a&gt; by Palantir Engineering Team&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackernoon.com/how-to-give-and-get-better-code-reviews-e011c3cda55e&quot;&gt;How to Give and Get Better Code Reviews&lt;/a&gt; by Tracy Lum&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://google.github.io/eng-practices/review/reviewer/looking-for.html&quot;&gt;Google’s Engineering Practices&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.blog/2019/09/30/how-to-make-good-code-reviews-better/&quot;&gt;10 Principles of a Good Code Review&lt;/a&gt; by Jason C. McDonald&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.blog/2019/09/30/how-to-make-good-code-reviews-better/&quot;&gt;How to Make Good Code Reviews Better&lt;/a&gt; by Gergely Orosz&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.pragmaticengineer.com/good-code-reviews-better-code-reviews/&quot;&gt;Good Code Reviews, Better Code Reviews&lt;/a&gt; by Gergely Orosz&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>The broken window principle applied to software</title>
   <link href="https://www.danielemargutti.com/2022/03/28/broken-window-principle-applied-to-software/"/>
   <updated>2022-03-28T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2022/03/28/broken-window-principle-applied-to-software</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.simplypsychology.org/broken-windows-theory.html&quot;&gt;“Broken Windows”&lt;/a&gt; is one of the most cited articles in the history of criminology. The theory was first suggested in the early 1980s by a social scientist, George L. Kelling, in &lt;a href=&quot;https://www.theatlantic.com/magazine/archive/1982/03/broken-windows/304465/&quot;&gt;his article in the Atlantic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It follows an experiment conducted by Standford’s psychologist Philip Zimbardo in 1969.
Kelling explained the theory as follows:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Consider a building with a few broken windows. If the windows are not repaired, the tendency is for vandals to break a few more windows. Eventually, they may even break into the building, and if it’s unoccupied, perhaps become squatters or light fires inside.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or, in a more lightweight version:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Consider a pavement. Some litter accumulates. Soon, more litter accumulates. Eventually, people even start leaving bags of refuse from take-out restaurants there or even break into cars.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you like the topic there is an entire literature on this subject; take a look at &lt;a href=&quot;https://www.amazon.com/exec/obidos/ASIN/0684837382/codihorr-20&quot;&gt;“Fixing Broken Windows”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://news.northeastern.edu/2019/05/15/northeastern-university-researchers-find-little-evidence-for-broken-windows-theory-say-neighborhood-disorder-doesnt-cause-crime/&quot;&gt;A 2019 study on this topic&lt;/a&gt;, revealed that the survey can be unreliable because people’s perception of the disorder in their neighborhoods may be intertwined with their assessments of crime as well as how they describe their own mental or physical health.&lt;/p&gt;

&lt;p&gt;In fact, he says that policing and public health strategies shouldn’t be based on the idea that disorder causes people to break the law or participate in dangerous or unhealthy behavior.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;However, that disorder, if studied in a more precise way, can provide valuable insight into what’s happening in neighborhoods and inform public policy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;an-insanely-detail-oriented-activity&quot;&gt;An insanely detail-oriented activity&lt;/h2&gt;

&lt;p&gt;Software Design is an insanely detail-oriented activity; while a broken window does not necessarily mean stolen wheels in a nearby car, the relationship between different components in software can be much much tighter.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When your team is not on top of the details, the general perception is that things are out of control, and it’s only a matter of time before your project spins out of control and everyone stops caring about maintenance &amp;amp; evolution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’ve been following me for some time, you will know already that I do not believe in perfectionism, especially in software design. No project is going to be perfect: in a highly mutable environment with constantly changing constraints you just can’t define a bullet points list with must-have conditions for perfection.
Nick Gracilla &lt;a href=&quot;https://typeshare.co/nickgracilla/posts/great-software-architecture-is-like-great-plumbingbut-for-a-house-thats-constantly-changing?utm_source=pocket_mylist&quot;&gt;explained this concept&lt;/a&gt; with a beautiful quote:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Great software architecture is like great plumbing — but for a house, that’s constantly changing&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Great software architecture is adaptable; it can handle the constant change businesses place on software and is ready for future iterations and the problem definition changes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OK, wait, wait. Let’s just back off for one second. What’s the “broken windows” theory in software design?&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;no-one-starts-with-bad-intents&quot;&gt;No one starts with bad intents&lt;/h2&gt;

&lt;p&gt;No one starts a project with the intent of making a bad job.
In the beginning, principles, practices, and laws are of primary interest, even if putting them into practice might prove difficult (it also depend on team skills)&lt;/p&gt;

&lt;p&gt;Suddenly a “window” is broken.&lt;br /&gt;
It may happen to high pressure to deliver or just a lack of knowledge.&lt;br /&gt;
People often make mistakes, even senior people. Especially senior people (“Your ego is your soul’s worst enemy” ~ Rusty Eric).
But Broken windows are not just a matter of mistakes; requirements often change and you may need to make small or big changes to follow the intents at the bests.&lt;br /&gt;
It’s only normal.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.theringer.com/movies/2018/4/24/17261506/sliding-doors-20th-anniversary&quot;&gt;Here there is a sliding door&lt;/a&gt;.&lt;br /&gt;
If no measures are taken &lt;a href=&quot;https://www.offnotes.org/the-economy-of-tech-debt/&quot;&gt;technical debt starts spreading&lt;/a&gt; and more “windows get broken”: issues propagate in the code through imitation (“I’ve just copied that” approach), repetition (a broken assumption), or just a copy+paste.&lt;/p&gt;

&lt;p&gt;The resulting system manifests &lt;em&gt;rigidity, fragility, immobility, and lower resilience over changes&lt;/em&gt;. Each new change comes with a high cost, an increment of changed parts, and therefore a high risk of failure.&lt;/p&gt;

&lt;h2 id=&quot;what-broken-window-theory-suggests&quot;&gt;What Broken Window Theory Suggests&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;When bad behavior is not corrected immediately, it just shows people that there is no downside to breaking the rules, practices, or standards.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The absence of any negative outcome spreads the intrinsic perception of the disorder; cutting the corners becomes acceptable and quality starts decreasing.&lt;/p&gt;

&lt;p&gt;While the problem might be complex to approach the solutions are simple:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Carry the healthy approach in your team&lt;/strong&gt; — Senior people wanna desperately demonstrate their strengths (I’m a f*ing 10x engineer baby!), junior people how much they can do. Rarely one, two, or three days more than the estimate means something. Instead, a calm and focused approach is what can save you and your team.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Nothing comes for free&lt;/strong&gt; — Everyone can rewrite software from the stretch; constant maintenance and evolution are far more difficult and show how you and your team are good at software design. Refactoring — like debugging — is an insightful activity to show the strengths of any developer.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Modern networking in Swift</title>
   <link href="https://www.danielemargutti.com/2022/03/16/realhttp/"/>
   <updated>2022-03-16T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2022/03/16/realhttp</id>
   <content type="html">&lt;p&gt;I’ve got a confession to make: Making networking layers has always been an exciting topic for me. Since the first days of iOS programming, in early 2007, each new project represented a fresh opportunity to refine or even break the entire approach I have used so far. My last attempt to write something on this topic &lt;a href=&quot;https://danielemargutti.medium.com/network-layers-in-swift-updated-version-539d9c636b8&quot;&gt;is dated 2017&lt;/a&gt;, and I considered it a milestone after the switch to Swift language.&lt;/p&gt;

&lt;p&gt;It’s been a long time since then; the language evolved like the system frameworks, and recently, with the introduction of the new &lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html&quot;&gt;Swift’s Concurrency Model&lt;/a&gt;, I decided to take a further step forward and update my approach to networking layers. This new version went through a radical redesign that allows you to write a request in just &lt;a href=&quot;https://github.com/immobiliare/RealHTTP&quot;&gt;a single line of code&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;todo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://jsonplaceholder.typicode.com/todos/1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Todo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this time, you may be thinking: why should I make my client instead of relying on Alamofire? You’re right. A new implementation is inevitably immature and a source of issues for a certain amount of time. Despite all, you have the opportunity to create a fine-tuned integration with your software and avoid third-party dependencies. Moreover, you can take advantage of the new Apple technologies like &lt;a href=&quot;https://developer.apple.com/documentation/foundation/urlsession&quot;&gt;URLSession&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/documentation/swift/codable&quot;&gt;Codable&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2021/10132/&quot;&gt;Async/Await&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2021/10133/&quot;&gt;Actors&lt;/a&gt;.&lt;br /&gt;
You can find the code on GitHub; the project is called &lt;a href=&quot;https://github.com/immobiliare/RealHTTP&quot;&gt;RealHTTP&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-client&quot;&gt;The Client&lt;/h2&gt;

&lt;p&gt;Let’s start by defining a type for representing a client. A client (formerly &lt;a href=&quot;https://github.com/immobiliare/RealHTTP/blob/main/Sources/RealHTTP/Client/HTTPClient/HTTPClient.swift&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPClient&lt;/code&gt;&lt;/a&gt;) is a structure that comes with cookies, headers, security options, validator rules, timeout, and all other shared settings you may have in common between a group of requests. When you run a request in a client, all these properties are automatically from the client unless you customize it in a single request.&lt;/p&gt;

&lt;p&gt;For example, when you execute an auth call and receive a JWT token, you may want to set the credentials at the client level, so any other request incorporate these data. The same happens with validators: to avoid duplicating the logic for data validation, you may want to create a new validator and let the client execute it for every request it fetches. A client is also an excellent candidate to implement retry mechanisms not available on basic URLSession implementation.&lt;/p&gt;

&lt;h2 id=&quot;the-request&quot;&gt;The Request&lt;/h2&gt;

&lt;p&gt;As you may imagine, a request (formerly &lt;a href=&quot;https://github.com/immobiliare/RealHTTP/blob/main/Sources/RealHTTP/Client/HTTPRequest/HTTPRequest.swift&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPRequest&lt;/code&gt;&lt;/a&gt;) encapsulate a single call to an endpoint.&lt;/p&gt;

&lt;p&gt;If you have read some other articles on this topic, you may find often a common choice is to use &lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Generics.html&quot;&gt;Swift’s Generic&lt;/a&gt; to handle the output of a request.&lt;br /&gt;
Something like: struct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPRequest&amp;lt;Response&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It allows you to strongly link the output object type to the request itself. While it’s a clever use of this fantastic construct, I found it makes the request a bit restrictive. From a practical perspective, you may need to use &lt;a href=&quot;https://fabernovel.github.io/2020-06-03/approaches-to-type-erasure-in-swift&quot;&gt;type erasure&lt;/a&gt; to handle this object outside its context. Also, conceptually, I prefer to keep the request stages (fetch ~&amp;gt; get raw data ~&amp;gt; object decode) separated and easily identifiable.&lt;/p&gt;

&lt;p&gt;For these reasons, I chose to avoid generics and return a raw response (HTTPResponse) from a request; the object will therefore include all the functions to allow easy decode (we’ll take a look at it below).&lt;/p&gt;

&lt;h2 id=&quot;configure-a-request&quot;&gt;Configure a Request&lt;/h2&gt;

&lt;p&gt;As we said, a request must allow us to easily set all the relevant attributes for a call, especially “HTTP Method” “Path,” “Query Variables,” and “Body.” What do Swift developers love more than anything else? Type-safety.&lt;/p&gt;

&lt;p&gt;I’ve accomplished it in two ways: using configuration objects instead of literal and protocols to provide an extensible configuration along with a set of pre-made builder functions.&lt;/p&gt;

&lt;p&gt;This is an example of request configuration:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPRequest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://.../login&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redirectMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maxRetries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;X-API-Experimental&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Setup URL query params &amp;amp; body&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addQueryParameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;full&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addQueryParameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;autosignout&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;30&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pwd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A typical example of type safety in action is the HTTP Method which became an enum; but also the headers which are managed using a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPHeader&lt;/code&gt; object, so you can write something like the following:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bmp&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bmp&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;X-Custom-Header&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;abc&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It supports both type-safe keys declaration and custom literal.&lt;/p&gt;

&lt;p&gt;The best example of the usage of protocols is the body setup of the request. While it’s ultimately a binary stream, I decided to create a struct to hold the data content and add a set of utility methods to make the most common body structures (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPBody&lt;/code&gt;): multi-part form, JSON encoded objects, input stream, URL encoded body, etc.&lt;/p&gt;

&lt;p&gt;The result is an:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Extensible interface&lt;/strong&gt;: you can create a custom body container for your own data structure and set them directly. Just make it conforms to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPSerializableBody&lt;/code&gt; protocol to allow the automatic serialization to data stream when needed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Easy to use APIs set&lt;/strong&gt;: you can create all of these containers directly from the static methods offered by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPBody&lt;/code&gt; struct&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s an example of a multipart form:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;multipart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;boundary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;param_1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mimeType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;some other&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;param_2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Making a body with a JSON encoded object is also one line of code away:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When a request is passed to a client, the associated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLSessionTask&lt;/code&gt; is created automatically (in another thread) and the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLSession&lt;/code&gt; flow is therefore executed. The underlying logic still uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLSessionDelegate&lt;/code&gt;(and the other delegates of the family); you can find more in the &lt;a href=&quot;https://github.com/immobiliare/RealHTTP/blob/main/Sources/RealHTTP/Client/Internal/HTTPDataLoader/HTTPDataLoader.swift&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPDataLoader&lt;/code&gt;&lt;/a&gt; class.&lt;/p&gt;

&lt;h2 id=&quot;execute-a-request&quot;&gt;Execute a Request&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPClient&lt;/code&gt; takes full advantage of async/await, returning the raw response from the server. Running a request is easy: just call its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch()&lt;/code&gt; function. It takes an optional client argument; if not set, the default singleton &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPClient&lt;/code&gt; instance is used (it means cookies, headers, and other configuration settings are related to this shared instance).&lt;/p&gt;

&lt;p&gt;Therefore, the request is added to the destination client and, accordingly with the configuration, will be executed asynchronously. Both serialization and deserialization of the data stream are made in another Task (for the sake of simplicity, another thread). This allows us to reduce the amount of work done on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPClient&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-response&quot;&gt;The Response&lt;/h2&gt;

&lt;p&gt;The request’s response is of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPResponse&lt;/code&gt;; this object encapsulates all the stuff about the operation, including the raw data, the status code, optional error (received from the server or generated by a response validator), and the metrics data valid for integration debugging purposes.&lt;/p&gt;

&lt;p&gt;The next step is to transform the raw response into a valid object (with/without a DAO). The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decode()&lt;/code&gt; function allows you to pass the expected output object class. Usually, it’s an Codable object, but it’s also essential to enable custom object decoding, so you can also use any object that conforms to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPDecodableResponse&lt;/code&gt; protocol. This protocol just defines a static function: static func decode(_ response: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPResponse&lt;/code&gt;) throws -&amp;gt; Self?.&lt;/p&gt;

&lt;p&gt;Implementing the custom decode() function, you can do whatever you want to get the expected output. For example, I’m a firm fan of SwiftyJSON. It initially may seem a little more verbose than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;‘Codable&lt;/code&gt;,’ but it also offers more flexibility over the edge cases, better failure handling, and a less opaque transformation process.&lt;/p&gt;

&lt;p&gt;Since most of the time, you may want just to end up with the output decoded object, the fetch() operation also presents the optional decode parameter, so you can do fetch &amp;amp; decode in a single pass without passing from the raw response.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;loggedUser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This alternate fetch() function combines both the fetch and decode in a single function; you may find it helpful when you don’t need to get the inner details of the response but just the decoded object.&lt;/p&gt;

&lt;h2 id=&quot;validatemodify-a-response&quot;&gt;Validate/Modify a Response&lt;/h2&gt;

&lt;p&gt;Using a custom client and not the shared one is to customize the logic behind the communication with your endpoint. For example, we would communicate with two different endpoints with different logic (oh man, the legacy environments…). It means both the result and errors are handled differently.&lt;/p&gt;

&lt;p&gt;For example, the old legacy system is far away from being a REST-like system and puts errors inside the request’s body; the new one uses the shiny HTTP status code.&lt;/p&gt;

&lt;p&gt;To handle these and more complex cases, we introduced the concept of response validators, which are very similar’s to Express’s Validators. Basically, a validator is defined by a protocol and a function that provides the request and its raw response, allowing you to decide the next step.&lt;/p&gt;

&lt;p&gt;You can refuse the response and throw an error, accept the response or modify it, make an immediate retry or retry after executing an alternate request (this is the example for an expired JWT token that needs to be refreshed before making a further attempt with the original request).&lt;/p&gt;

&lt;p&gt;Validators are executed in order before the response is sent to the application’s level. You can assign multiple validators to the client, and all of them can concur to the final output. This is a simplified version of the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPResponseValidator&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forRequest&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPResponseValidatorResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// invalid response, we want to fail the request with error&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPError&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;invalidResponse&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nextValidator&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// everything is okay, move to next validator&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can extend/configure it with different behavior. Moreover, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPAltResponseValidator&lt;/code&gt; is the right validator to implement retry/after call logic. A validator can return one of the following actions defined by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPResponseValidatorResult&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nextValidator&lt;/code&gt;: just pass the handle to the next validator&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;failChain&lt;/code&gt;: stop the chain and return an error for that request&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;retry&lt;/code&gt;: retry the origin request with a strategy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;retry-strategy&quot;&gt;Retry Strategy&lt;/h2&gt;

&lt;p&gt;One of the advantages of Alamofire is the infrastructure for adapting and retrying requests. Reimplementing it with callbacks is far from easy, but with async/await, it’s way easier. We want to implement two kinds of retry strategies: a simple retry with delay and a more complex one to execute an alternate call followed by the origin request.&lt;/p&gt;

&lt;p&gt;Retry strategies are handled inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLSessionDelegate&lt;/code&gt; which is managed by a custom internal object called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPDataLoader&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The following is an over-simplified version of the logic you can find here(along with comments):&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// prepare the request and execute it&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;urlSessionTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;inClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;sessionTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ask to validator the action to perform on this request&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;forRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;failChain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// fail with error&lt;/span&gt;
                
       &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isAltRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reachedMaxRetries&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// alt request cannot be retried to avoid infinite loops&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// perform retry strategy&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;retryResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;performRetryStrategy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                              &lt;span class=&quot;nv&quot;&gt;forRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sessionTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;nv&quot;&gt;withResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;retryResponse&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;nextValidator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// validation okay&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you are thinking about using auto-retries for connectivity issues, consider using &lt;a href=&quot;https://developer.apple.com/documentation/foundation/urlsessionconfiguration/2908812-waitsforconnectivity&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;waitsForConnectivity&lt;/code&gt;&lt;/a&gt; instead. If the request does fail with a network issue, it’s usually best to communicate an error to the user. With &lt;a href=&quot;https://developer.apple.com/documentation/network/nwpathmonitor&quot;&gt;NWPathMonitor&lt;/a&gt; you can still monitor the connection to your server and retry automatically.&lt;/p&gt;

&lt;h2 id=&quot;debugging&quot;&gt;Debugging&lt;/h2&gt;

&lt;p&gt;Debugging is important; a standard way to exchange networking calls with backend teams is cURL. It doesn’t need an introduction. There is an extensionboth for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPRequest&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPResponse&lt;/code&gt; which generates a cURL command for the underlying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLRequest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ideally, you should call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cURLDescription&lt;/code&gt; on request/response and you will get all the information automatically, including the parent’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTPClient&lt;/code&gt; settings.&lt;/p&gt;

&lt;h2 id=&quot;other-features&quot;&gt;Other Features&lt;/h2&gt;

&lt;p&gt;This article would have been a lot longer. We didn’t cover topics like SSL Pinning, Large File Download/Resume, Requests Mocking, and HTTP Caching. All these features are currently implemented and working on the GitHub project, so if you are interested you can look directly at sources. By the way, I’ve reused the same approaches you have seen above.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How Feature Flags can boost your mobile app</title>
   <link href="https://www.danielemargutti.com/2022/01/26/how-feature-flags-can-boost-your-mobile-app/"/>
   <updated>2022-01-26T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2022/01/26/how-feature-flags-can-boost-your-mobile-app</id>
   <content type="html">&lt;p&gt;Modern mobile development moves quickly; here in our team, we release a new version of our iOS app every two weeks.&lt;/p&gt;

&lt;p&gt;If you are lucky enough to live the moment of a team expansion you will also see the exact moment where everything starts slowing down because you have multiple in-progress things that aren’t quite ready for production.&lt;/p&gt;

&lt;p&gt;It’s a typical scaling problem where you need to rethink how you and your team perform everyday jobs (if you are experiencing this transition you should really take a look at &lt;a href=&quot;https://www.mobileatscale.com/&quot;&gt;“Mobile Apps at Scale”&lt;/a&gt; by Gergely Orosz).&lt;/p&gt;

&lt;p&gt;Great features take time to build. How do you let the team work efficiently — free to experiment — whilst keeping the app in a releasable state?&lt;/p&gt;

&lt;p&gt;Feature Flags is one of the strategies you can use to better handle the increase of traffic in your team repositories.&lt;/p&gt;

&lt;h2 id=&quot;whats-a-feature-flag&quot;&gt;What’s a Feature Flag?&lt;/h2&gt;

&lt;p&gt;Some people call them “Feature Toggles”, some other “Feature Switch” or “Feature Controls”. All of them are names for a feature management solution that enables developers or product manager to change product’s functionality without deploying new code.&lt;/p&gt;

&lt;p&gt;You can consider a feature flag as a decision stop-point in your code that can change the behavior of your product. You may choose to allow developers/tester/product team to adjust these values at runtime.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“(…) feature flagging is to experimentation as machine learning is to AI, you cannot have the second without the first one”
JustEat Tech Blog&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;common-scenarios&quot;&gt;Common Scenarios&lt;/h2&gt;

&lt;p&gt;Feature flags are helpful for numerous scenarios typical with mobile development teams.&lt;/p&gt;

&lt;h3 id=&quot;avoid-long-lasting-branches&quot;&gt;Avoid Long-Lasting Branches&lt;/h3&gt;

&lt;p&gt;In this environment, you can let developers merge in their code without working on long-lasting branches (every dev hates resolving boring merge conflicts every time for days or, worse, entire weeks).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Feature flags allows to keep your MRs small &amp;amp; focused, the main branch can be continuously updated and you can release nightly builds with no worries (*).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;reduce-the-risk&quot;&gt;Reduce the risk&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bugs happen — even with the best developers and rigorous testing techniques&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine this: after months of work-in-progress your team have just release a new amazing feature and you’re exicited for your users to try it out. Unfortunately, things don’t go the way you thought they would and you found an unexpected bug. Now you can either deploy an hot fix or revert the feature.&lt;/p&gt;

&lt;p&gt;However, deploying mobile apps is not easy as for web apps or sites and with the app review you may wait 1–2 days. That’s terrible as you risk losing users.&lt;br /&gt;
You have to do something immediately!&lt;br /&gt;
With remote-controlled flags, you can temporarily disable the feature while taking your time to release the hotfix.&lt;/p&gt;

&lt;h3 id=&quot;ab-testing&quot;&gt;A/B Testing&lt;/h3&gt;

&lt;p&gt;Feature flags can be used to activate different experiences for sets of users. You can, for example, divide your user base into several sections and measure the conversion performance in order to pick the higher product conversions, engagement, growth, subscription rates, or revenue.&lt;/p&gt;

&lt;h3 id=&quot;product-campaignsearly-access&quot;&gt;Product Campaigns/Early Access&lt;/h3&gt;

&lt;p&gt;Product and marketing teams can safely roll out features when they are ready, from remote. They can grant access to a feature to a group of elite users or new users to drive engagement.&lt;/p&gt;

&lt;h3 id=&quot;our-development-scenario&quot;&gt;Our Development Scenario&lt;/h3&gt;

&lt;p&gt;In our team, we use feature flagging to gate in-progress features so we can continue to build &amp;amp; test them without exposing them to end-users before they’re ready. Merge Requests are short and focused and enter into the main branch even if they are not complete yet. Obviously, they are disabled by default until everything is ready, but the team can continue the standard release cycle.&lt;/p&gt;

&lt;p&gt;To make it effortless, at the iOS team we’ve developed an in-house opensource library named &lt;a href=&quot;https://github.com/immobiliare/RealFlags&quot;&gt;RealFlags&lt;/a&gt; to handle feature flags without the hassle. The idea behind the library is to use the best of new Swift language features to create a powerful abstraction layer over multiple providers you can use to setup your experiment lab.RealFlags born with Swift in mind and the vast majority of the core concepts we used to make it are introduced in the current major 5.x.&lt;/p&gt;

&lt;p&gt;In the post below I’ll describe the architecture and the core engine with code samples and suggestions based on our experience. I should like to thank several open-source libraries who inspired the work below: [JustTweak(https://github.com/justeat/JustTweak)] by JustEat, &lt;a href=&quot;https://github.com/yahoo/Override&quot;&gt;Override&lt;/a&gt; by Yahoo and &lt;a href=&quot;https://github.com/rwbutler/FeatureFlags&quot;&gt;FeatureFlags&lt;/a&gt; by Ross Butler.&lt;/p&gt;

&lt;h2 id=&quot;what-you-want-from-feature-flags&quot;&gt;What you want from Feature Flags&lt;/h2&gt;

&lt;p&gt;As I said a the beginning of the post, mobile development moves quickly; the product still evolving, constraints change, your code easily becomes a legacy code you need to refactor.&lt;/p&gt;

&lt;p&gt;Our new Swift app was born less than 4 years ago but during this period we rewrote several parts: feature flags helped us to make this process gradual. In fact, we moved from old to new implementations in a way transparent to the end user.&lt;/p&gt;

&lt;p&gt;But a product is not only a tech affair (some devs tend for forget it). As a continuous experiment your product team would introduce new features, enable/disable existing ones via A/B testing, and so on.&lt;/p&gt;

&lt;p&gt;So the feature flag engine must fulfill these requirements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;It’s simple&lt;/strong&gt; — The goal is to hide the complexity as much as possible. Your team must be able to define and manage feature flags easily.In fact you should indirect encourage devs to use them.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It’s a gateway&lt;/strong&gt; — It must act as a gateway for unfinished features. Devs/qa/product must be able to test them development process is going while the release cycle can continue with no stops.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It encourages good habits&lt;/strong&gt; — Flags must be self-describing and easy to be organized: you may end with many different feature flags in place. The likelihood of getting lost in confusion is high and you don’t certainly want to waste your time searching where the flag is and what it means. The library itself should call on good habits.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It’s abstract&lt;/strong&gt; — You don’t want to rely on a specific service only to waste time and resources rewriting all from the scratch when your product team will decide to move all to something else.Third-party SDKs are not under your team control and it’s different to support multiple feature flags providers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It support different datatypes&lt;/strong&gt; — Typically a feature flag is just a boolean value but you need to use Int, Float, String or your own structs, enum or classes! You should be able to save and set them easily.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Feature flags are discoverable&lt;/strong&gt; — In order to simplify your dev job and allow qa/product to play with flags, you should prepare a great user interface to browse and alter values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[RealFlags(https://github.com/immobiliare/RealFlags)] acts as an orchestration library both when you need to choose as organize your flags and how to query for values.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;RealFlags provides a simple UI to interact and modify your flags. Feature flags are organized in collections; you can define collections by using your own criteria.Once done you can add some sort of hidden menu section of your app and tell the browser to show them.&lt;/p&gt;

&lt;p&gt;Below you can see the RealFlags menu which perfectly fits in our Developer Tools menu. This section is still visible only when the app is running in debug or from a TestFlight installation.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;lazy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;shouldShowDevMenu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;#if DEBUG&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// XCode&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;#else&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bundle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;appStoreReceiptURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// AppStore&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sandboxReceipt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// TestFlight&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;#endif&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have different flags and we have choosen to organize them by conpetence area with a final collection dedicated to remote controlled flags.&lt;/p&gt;

&lt;p&gt;At the time of this writing, RealFlag’s last version is 1.2.0; you can use it via CocoaPods or &lt;a href=&quot;https://github.com/immobiliare/RealFlags#installation&quot;&gt;SPM&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;p&gt;It’s time to setup your stack; now you’re ready to create your first collection. Suppose you wanna make a section dedicated to the user’s experimental features.&lt;/p&gt;

&lt;p&gt;We’ll call it UserExperiments: in this section product team can enable or disable some amazing features. Some flags may also be controlled from remote using &lt;a href=&quot;https://firebase.google.com/products/remote-config?gclid=CjwKCAiA866PBhAYEiwANkIneKXiDQpTt25Nr-5kQdFylYUMTRO0QouOrgAajsbt9HJG5fRz6yVujBoCysMQAvD_BwE&amp;amp;gclsrc=aw.ds&quot;&gt;Firebase Remote Config&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As good habit RealFlags allows you to declare the blueprint of the collection (a collection is a struct conforms to FlagCollectionProtocol) including the inner flags. While you can create collections of collections I strongly suggest to avoid it for the sake of clarity.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UserExperiments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FlagsCollectionProtocol&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;// ....&lt;/span&gt;
   &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A feature flag is just a variable wrapped by @Flag decorator. Technically speaking it’s a &lt;a href=&quot;https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md&quot;&gt;Property Wrapper&lt;/a&gt; that defines all the attributes and metadata of the flag. In short, a property wrapper is a generic data structure that encapsulates read/write access to property while adding some extra behavior to augment its semantics while avoiding code duplication.&lt;/p&gt;

&lt;p&gt;Suppose you want to create a enableSSON flag which allows the user to use single-sign-on to login inside the app.
By default this flag is turned off:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UserExperiments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FlagsCollectionProtocol&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   
   &lt;span class=&quot;kd&quot;&gt;@Flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;sson&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Enable Single-Sign-On&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;allowsSSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
   
   &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allowsSSOn&lt;/code&gt; is a Bool flag which by default is false (RealFlags supports Int, String, Data, Date, URL, Dictionary, JSON and &lt;a href=&quot;https://github.com/immobiliare/RealFlags/blob/main/documentation/introduction.md#12--flag-supported-data-types&quot;&gt;all the data types conforms to Codable&lt;/a&gt;) which .&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;description&lt;/code&gt; field is used to describe the flag inside the browser so be careful when you fill it. We have also specified key: it represent the string RealFlags will use to query every Data Provider (you can configure it as &lt;a href=&quot;https://github.com/immobiliare/RealFlags/blob/main/documentation/introduction.md#16-configure-key-evaluation-for-flagsloaders-flag&quot;&gt;you wish&lt;/a&gt;). You can also set more &lt;a href=&quot;https://github.com/immobiliare/RealFlags/blob/main/documentation/introduction.md#11-flag-annotation&quot;&gt;configuration parameters&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A Data Provider is just a source of data; when you query for a value of a flags, RealFlags query — in order — every provider gets the value for that key. The first one who responds with a non-nil value stops the chain with that value. If no data provider is able to respond (or you have not defined any provider) the default value is therefore returned.&lt;/p&gt;

&lt;h2 id=&quot;load-a-collection&quot;&gt;Load a Collection&lt;/h2&gt;

&lt;p&gt;Since the code above it’s only a blueprint of our collection, now we need to load it. FlagsLoader is a &lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Generics.html&quot;&gt;Generic-aware&lt;/a&gt; class responsible to read (via mirroring) the structure of a collection.&lt;/p&gt;

&lt;p&gt;Typically you would use a single loader to handle a single collection. When you instantiate a loader you will also specify - in order - the Data Providers you wanna use to query each flag’s value (note: you can still exclude some data providers per single flag or query a specific data provider type when you want to get the value of a flag).&lt;/p&gt;

&lt;p&gt;Actually, you can choose two different Data Providers (but you can easily make your own as you need):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LocalProvider&lt;/code&gt;: it’s a writable provider. It allows you to load and set values locally inside the sandbox by just providing the URL to a file destination.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FirebaseRemoteProvider&lt;/code&gt;: it’s a read-only provider; allows you to get values directly from a pre-configured session of Firebase (keep in mind: your Firebase must be configured via FirebaseApp.configure() before calling this provider).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FFService&lt;/code&gt; is a simple helper class inside our app that holds the value of any loader:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FFService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FFService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FlagLoader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UserExperiments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FileManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documentDirectory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userDomainMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;appendingPathComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_flags.xml&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FlagsLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UserExperiments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;User Features&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Experimental lab&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                                  &lt;span class=&quot;nv&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                                     &lt;span class=&quot;kt&quot;&gt;FirebaseRemoteProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                                     &lt;span class=&quot;kt&quot;&gt;LocalProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;localURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                  &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The order of the data provider in the init defines the query priority. When fetching a flag, the engine will inspect the chain of providers in order and pick the flag from the first configuration having it.&lt;/p&gt;

&lt;h2 id=&quot;query-for-values&quot;&gt;Query for values&lt;/h2&gt;

&lt;p&gt;Now you are able to query for User Experimental features by calling userExpsLoader: thanks to DynamicMemberLookup. Xcode will autocomplete for you each flag defined by the collection. Just magic!&lt;/p&gt;

&lt;p&gt;Sometimes you may want to get the value of the flag inside a specific provider. In this case, you may refer to the projected value. We will get the value of LocalProvider by ignoring the Firebase which has a higher priority in our loader:&lt;/p&gt;

&lt;p&gt;As we said we may have nested collections:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UserExperiments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FlagCollectionProtocol&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;@FlagCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;A nested collection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;SecretsExperiments&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;@Flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;sson&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Enable Single-Sign-On&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;allowsSSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;SecretsExperiments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FlagCollectionProtocol&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;@Flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Risky feature!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;boomFeature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But, what’s the key queried for boomFeature? If you don’t specify the key for a flag the snake_case version of the variable name is combined with the path down to the variable itself. In this case the key queried is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secrets/boom_feature&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;set-values&quot;&gt;Set Values&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LocalProvider&lt;/code&gt; is an example of a writable Data Provider: this means you can alter a flag value and it persists between app launches.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;FFService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;$allowsSSON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;LocalProvider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since we maintain several target applications for different countries we have used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setValue()&lt;/code&gt; to keep a single blueprint file of definitions while altering default values inside a conditional init:&lt;/p&gt;

&lt;h2 id=&quot;computed-flag&quot;&gt;Computed flag&lt;/h2&gt;

&lt;p&gt;Sometimes you may need to create a feature flag where the value is a combination of other flags or runtime values you need to evaluate dynamically.&lt;/p&gt;

&lt;p&gt;This is the perfect example to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;computedValue&lt;/code&gt; which is just a &lt;a href=&quot;https://github.com/immobiliare/RealFlags/blob/main/documentation/introduction.md#14-computed-flag&quot;&gt;callback&lt;/a&gt; function called before querying any data provider. Returning a non-nil value here stops the chain.&lt;/p&gt;

&lt;p&gt;Our suggestion is to limit the use of this pattern in order to keep the code readable. We have introduced it to handle several edge cases we have in our app.&lt;/p&gt;

&lt;h2 id=&quot;show-the-browser&quot;&gt;Show the browser&lt;/h2&gt;

&lt;p&gt;We started looking at the feature flag browser. But we haven’t said how to show it. That’s simple:&lt;/p&gt;

&lt;p&gt;In this article, I illustrated how &lt;a href=&quot;https://github.com/immobiliare/RealFlags&quot;&gt;RealFlags&lt;/a&gt; can be a great help in adding an abstract yet flexible approach to feature flagging.&lt;/p&gt;

&lt;p&gt;Currently, we’re using it in our flagship product; if you want to contribute, provide additional features or providers check out the &lt;a href=&quot;https://github.com/immobiliare/RealFlags&quot;&gt;Github project page&lt;/a&gt;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The economy of tech debt</title>
   <link href="https://www.danielemargutti.com/2022/01/10/the-economy-of-tech-debt/"/>
   <updated>2022-01-10T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/2022/01/10/the-economy-of-tech-debt</id>
   <content type="html">&lt;p&gt;Most articles about tech debt are pretty much theory only with lots of interesting philosophies. I’d like to approach this topic in two steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The first part of this article is all about theory: what’s a tech debt, what’s not, and what’s the root causes and impacts on product and team.&lt;/li&gt;
  &lt;li&gt;In the second part, I’m going to give you a hands-on approach to how to manage it so you can improve your product time-to-market.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;whats-tech-debt&quot;&gt;What’s Tech Debt&lt;/h2&gt;

&lt;p&gt;Tech Debt is a concept in software development that reflects the implied cost of additional rework caused by choosing an easy (limited) solution now instead of using a better approach that would take longer.&lt;/p&gt;

&lt;p&gt;It was introduced by &lt;a href=&quot;https://en.wikipedia.org/wiki/Ward_Cunningham&quot;&gt;Ward Cunningham&lt;/a&gt; with the following words:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Shipping first-time code is like going into debt. A little debt speeds development so long as it is paid back promptly with refactoring. The danger occurs when the debt is not repaid.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, in fact:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Is not something &lt;em&gt;necessarily wrong&lt;/em&gt;, nor is it inherently right&lt;/li&gt;
  &lt;li&gt;It is &lt;em&gt;potentially dangerous&lt;/em&gt; when left unpaid (it can stack up quickly and easily)
This means we can accept some degree of tech debt during the development and be sure to constantly keep it in check.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;whats-not-tech-debt&quot;&gt;What’s Not Tech Debt&lt;/h2&gt;

&lt;p&gt;It is often much easier to put all the mess under the tech debt umbrella, but there is some stuff that is not eligible as tech debt, like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Legacy Code&lt;/strong&gt; As long it’s tested/properly written, legacy code is boring code you should not have fun rewriting once again.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Trending Techie&lt;/strong&gt; Don’t be such a baby; if it’s not the FoTM it’s great anyway.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Multiple Design Patterns&lt;/strong&gt; As much as you can appreciate a common design pattern inside a product, as long as the code is properly written, it’s not a problem nor a tech debt&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Code Guidelines&lt;/strong&gt; Same of above, feel free people having some uniqueness&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;measure-it&quot;&gt;Measure It&lt;/h2&gt;

&lt;p&gt;Before you consider any action, you need to measure it: a good metric to evaluate tech debt and plan any action is the amount of unplanned work.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Not all of the technical debt is worth repaying&lt;/strong&gt;
Usually when the time spent refactoring exceed the benefits it’s probably a better idea to just ignore the debt (note: you should still keep the track of it, where it lays and why you have decided to not address).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unplanned work is any task due to bugs, service interruptions, or flawed software designs.&lt;br /&gt;
Statistically has been shown that unplanned work should represent from 5% to 15% of the work of an organization.&lt;br /&gt;
When it goes higher, it should be accurately monitored in order to avoid further problems.&lt;/p&gt;

&lt;h2 id=&quot;root-causes&quot;&gt;Root Causes&lt;/h2&gt;

&lt;p&gt;Unplanned work, and therefore tech debt, have 3 different root causes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Time Pressure&lt;/strong&gt; We know deadlines are part of any business. Without setting deadlines, everything is bound to collapse. However, time pressure inevitably leads to corner-cutting, which means tech debt. Beware of artificial ship dates because they lead to hidden costs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Team Changes&lt;/strong&gt; Teams are living creatures; they change over time (and that’s good news, indeed). When new people come into the team, they typically have steep learning curves to learn what has come before. Learning is far from perfect.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pivots&lt;/strong&gt; Engineering teams hate that, but pivots are a fundamental part of business reality. The alternative to pivoting is flogging a dead horse. However, pivots lead to stretching existing implementations to fit new objectives; eventually, things may break.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Mounting tech debt means spread of unmanaged complexity, resulting in less business value being unlocked.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Why?&lt;/em&gt;&lt;br /&gt;
Simpler tasks require unnecessary cognitive load, which means more [shitty] work to get done and longer delivery times. Moreover, the result is anything but good, and the situation is going to get worse once new debts are going to be added.&lt;/p&gt;

&lt;p&gt;Impacts are on the tech side:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Performance/Stability&lt;/strong&gt; The responsiveness and the overall stability of the application&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Changeability&lt;/strong&gt; Likelihood of introducing new defects while changing existing features or adding new ones&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt; The ability of your application to prevent unauthorized intrusions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;… but also for the team:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Morale&lt;/strong&gt; The mess of tech debt slows developers down and sometimes even prevents them from doing their job. It can make it difficult to be proud of the work you’re doing as a lot of time is lost dealing with annoying problems (moreover invisible to product stakeholders).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transferability&lt;/strong&gt; The ease with which new developers can onboard into the product.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Retainability&lt;/strong&gt; 51% of engineers consider quitting their job due to tech debt (read more)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;learn-how-to-communicate-manage--minimize-the-impacts-of-tech-debt-in-your-code&quot;&gt;Learn how to Communicate, Manage &amp;amp; Minimize the Impacts of tech debt in your code.&lt;/h2&gt;

&lt;h3 id=&quot;communicate-effectively&quot;&gt;Communicate Effectively&lt;/h3&gt;

&lt;p&gt;Discussing tech debt with nontech people may be hard.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The secret here is to speak the language of business:
Persuade your stakeholders that time improving the product behind the scenes will increase productivity, sustainability, and scalability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The focus is always on cost and time instead of quality&lt;/strong&gt; Unmanaged tech debt increase the volatility in the marginal cost of features (aka. longer development times for new/existing features).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Collect Data&lt;/strong&gt; Measure measure measure: the number of bugs reported and accumulated per week, emergencies that occur per week, and so on. The point is to deliver your message along with measurable data. Because data are money.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Invest to save&lt;/strong&gt; Investing 10-15% of our time in code quality help to reduce developers’ turnover. How much does it cost us to replace a leaving dev?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;make-the-waste-visible&quot;&gt;Make the waste visible&lt;/h2&gt;

&lt;p&gt;The difference between financial debt and technical debt is visibility.
It’s not always clear how much technical debt you have at any time.
A tech debt follows 3 different stages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Unknown&lt;/strong&gt; As you may imagine, this is tech debt that you simply haven’t identified and have no idea it even exists. Uncertainty makes this debt the most dangerous type: you can’t consider it in future tasks without knowing of its existence. This is the reason for missed deadlines, blocks, and unforeseen issues.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dormant&lt;/strong&gt; You know about it, but you don’t plan to address it now. You can spot this debt while working on something, eventually in some old codebase. The best thing you can do is to take a note and face it later in the distant future. It’s perfectly healthy to have.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Active&lt;/strong&gt; You know about it, it’s defined, and you are able to plan a schedule to fix it in the foreseeable future. A common example you may incur active tech debt is when introducing a new feature following a strict deadline; the result may be less-than-ideal, but you plan actively fix it in a minor update after the release. Also, Active Debt is perfectly healthy to have.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As tech team, you’re like gardeners managing a green park along each season of the year. It’s springtime: you enthusiastically spend a large sum at the garden center and work your soil adding new plants (features) and architecting each garden (organizing your infrastructure).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Discipline is a fundamental part of your work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You must be diligent, regularly tame and tends their urban oasis, ripping out weeds, and ultimately end up with a beautiful park (congrats, you are managing tech debts!).
Failing to do regular maintenance, you eventually end up with a mess of dead plants everywhere, a dense forest, and frustration.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The goal is to make the waste visible, then schedule a plan to fix them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Like working in a garden, software needs time and resources to keep it sustainable and avoid long-term costs.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The biggest symptom of tech debt in an average software is a specific issue or issues correlated to each other (by technical dependency) with a moderate/high occurrence-rate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;hands-on-approach&quot;&gt;Hands-On Approach&lt;/h2&gt;

&lt;p&gt;As with any good plan, it starts measuring the impact.&lt;br /&gt;
You can’t plan or prioritize anything without knowing its impact.&lt;br /&gt;
Can’t avoid it, your job is to monitor where it is easy to find.&lt;br /&gt;
Once you spot it, take a deep breath and avoid fixing it immediately.&lt;br /&gt;
Annotate it in your backlog along with a meaningful description or a grade.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Tracking tech debts has a similar lifecycle of any product activity.
Start grading your debt on 4 levels with a values between 1 (light) to 5 (heavy).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Severity:&lt;/strong&gt; defines how much the user is disturbed/prevented from using your product. Show-stoppers or tech debt inside core parts of any foundation layer should be addressed urgently (level 5). Users rely on it, and you are likely to want to continue to develop those features. certainly, continuing to build on shaky foundations is far from an optimal solution.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Occurrence:&lt;/strong&gt; the number of times any user encounter the issue. Be sure to correctly link the tech error with the issue (1-5 at least in the top 5 of tracking occurrences)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dependency:&lt;/strong&gt; How much the issue is linked to other dependencies (aka. you should also touch other parts of the code).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now put all issues in an ordered list with those total grades.&lt;br /&gt;
That’s your priority.&lt;/p&gt;

&lt;h3 id=&quot;allocate-time-in-each-cycle&quot;&gt;Allocate time in each cycle&lt;/h3&gt;

&lt;p&gt;In my team, we have reserved part of any sprint (2 weeks) for addressing tech debt.
The amount of this time may vary depending on a lot of factors (how big the activity is, pressure to deliver other product-related features…), but you should consider a dedicated slot (~20%) for each iteration.
If you can’t commit to a fixed amount of time for each iteration, use the end of a quarter as a suitable time to do this.&lt;/p&gt;

&lt;h3 id=&quot;beware-artificial-deadlines&quot;&gt;Beware Artificial Deadlines&lt;/h3&gt;

&lt;p&gt;Deadlines can be real or artificial. Most of the time, artificial deadlines are used to set boundaries for all people involved. However, the hidden cost of an artificial deadline is a tech debt: while you think you can address a debt just after the release, instead, you may end up using the time supporting early changes and defects found.&lt;/p&gt;

&lt;h2 id=&quot;minimize-impacts&quot;&gt;Minimize Impacts&lt;/h2&gt;

&lt;p&gt;I’m sure you land in this paragraph hoping for a simple and fast answer.
At this time, you should have learned you can’t avoid Tech Debt completely.
It’s an inevitable part of shipping a product.&lt;/p&gt;

&lt;p&gt;But don’t be discouraged; it doesn’t mean you can’t take some actions to minimize it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Consistently refactoring the codebase&lt;/strong&gt; In our team, we often joke about continuous refactoring, but a disciplined approach to refactoring leads to a codebase that is low-maintenance, highly readable as well as highly functional, all while bringing down technical debt.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A common known enemy&lt;/strong&gt; Engineers waste more than seven hours per week on tech debt which is often invisible to stakeholders. Communicate the value of paying down technical debt to the product owner and stakeholders in your organization to make sure you have a common understanding.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Be aware of ninja devs&lt;/strong&gt; Finding talent that can create a working solution is not enough: it is also necessary to find talent that diligently creates a solution that is as sustainable as it is functional. Be aware of the ninja devs in your team.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Encourage cross-collaboration&lt;/strong&gt; Everyone should have a robust understanding of how core stuff works in the project; pair programming and cross-reviews must be part of the workflow.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Take time&lt;/strong&gt; Expect to spend a chunk of time/money after each major feature release to address the Tech Debt accumulated during the push to get the feature over the finish line.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Don’t write twice&lt;/strong&gt; MVP (Minimum Viable Product) is a critical part of each fast-moving business. You can’t afford to write things twice: produced code should be part of the product for a reasonable amount of time, so you need to make a plan even for an MVP. This doesn’t mean over-engineer; it means engineer once.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Tech Debt is an evitable output of any development activity. Not all of the technical debt is worth repaying (see time/benefits – &lt;a href=&quot;https://www.oliverwyman.com/our-expertise/insights/2021/oct/three-issues-that-sum-up-technical-debt.html&quot;&gt;check out this article&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Consider investing 15-20% of each iteration for maintenance and improvements requested by your team (read more)&lt;/li&gt;
  &lt;li&gt;Tracking &amp;amp; classification is fundamental; instill good habits in your team (&lt;a href=&quot;https://dev.to/dmitryame/addressing-product-delivery-debt-4pc3&quot;&gt;read more&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;Speak to nontechnical stakeholders using business terms (&lt;a href=&quot;https://understandlegacycode.com/blog/5-arguments-to-make-managers-care-about-technical-debt/&quot;&gt;check out this article&lt;/a&gt; for some examples)&lt;/li&gt;
  &lt;li&gt;Tech Debt also impacts team morale (see “State of Technical Debt 2021”)&lt;/li&gt;
  &lt;li&gt;Propose a &lt;a href=&quot;https://increment.com/planning/reframing-tech-debt/&quot;&gt;Tech Wealth culture&lt;/a&gt; in your organization&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 

</feed>
