<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gio Lodi</title>
    <description>The latest articles on DEV Community by Gio Lodi (@mokagio).</description>
    <link>https://dev.to/mokagio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95330%2Fb45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg</url>
      <title>DEV Community: Gio Lodi</title>
      <link>https://dev.to/mokagio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mokagio"/>
    <language>en</language>
    <item>
      <title>Don't check your inbox. Process it!</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Wed, 02 Aug 2023 20:22:36 +0000</pubDate>
      <link>https://dev.to/mokagio/dont-check-your-inbox-process-it-34fe</link>
      <guid>https://dev.to/mokagio/dont-check-your-inbox-process-it-34fe</guid>
      <description>&lt;p&gt;Do you ever find yourself filling moments of boredom by checking your inbox?&lt;/p&gt;

&lt;p&gt;Maybe you're waiting for a build to compile, and you go check Slack.&lt;br&gt;
Or perhaps your manager is late for the one-on-one meeting, and you scroll through emails in the meantime?&lt;/p&gt;

&lt;p&gt;Harmless on the surface, a quick inbox check is dangerous both in the moment and in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quick check trap
&lt;/h2&gt;

&lt;p&gt;One problem with inboxes is that you never know what you might find in there.&lt;br&gt;
The more people have access to you, the higher the chance you'll find messages requiring your attention in there.&lt;/p&gt;

&lt;p&gt;Especially in big organizations, your inbox will often contain a question from a colleague, a comment that rubs you the wrong way, or a link to an article that will capture your attention.&lt;br&gt;
Whatever you find on your "quick check" will force you to context switch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context switching is the number one enemy of cognitive efficiency.&lt;/strong&gt;&lt;br&gt;
Our brains cannot seamlessly switch between tasks.&lt;br&gt;
There's a cost to pay every time.&lt;/p&gt;

&lt;p&gt;UNI professor Gloria Mark has spent her career studying people's attention in the workplace.&lt;br&gt;
Here's what she writes in her book &lt;a href="https://geni.us/w5oqAu"&gt;Attention Span&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When people switch attention between different tasks [...] they need to reconfigure their internal representation of one task to the internal representation of the next task."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Reconfiguring one's internal representation is a gradual process that takes time to complete.&lt;br&gt;
The contents of the previous center of our attention remain in the periphery afterward, reducing the available mental bandwidth.&lt;/p&gt;

&lt;p&gt;Again from Gloria Mark:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rapid attention-shifting has repercussions on our ability to process information.&lt;br&gt;
What one looked at previously can interfere with what one is currently looking at.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interruptions and context-switching decrease the quality of our focus and, in turn, compromise the quality of our results.&lt;/p&gt;

&lt;p&gt;If you want to protect your ability to perform, you must be careful in how you interact with your inboxes.&lt;br&gt;
Stop checking. Process them instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  From checking to processing
&lt;/h2&gt;

&lt;p&gt;Processing an inbox means working through each new item and deciding what to do with it.&lt;br&gt;
Should it be addressed immediately, or can it be scheduled?&lt;br&gt;
Can you delegate it?&lt;br&gt;
Is it something you might need in the future?&lt;br&gt;
Do you need to update your daily plan because of the new information the item carries?&lt;/p&gt;

&lt;p&gt;Notice how this approach is intentional and focused.&lt;br&gt;
It requires shifting gears into planning mode and big-picture thinking.&lt;br&gt;
This kind of interaction with your inbox can only be achieved if you give it your full attention, not while you are already deep into something else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat looking at your inboxes like a standalone task, not a time-filler.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From reactive to proactive
&lt;/h2&gt;

&lt;p&gt;Checking your inbox while waiting for something is a reaction to boredom.&lt;/p&gt;

&lt;p&gt;Our brains crave novelty.&lt;br&gt;
When faced with a hint of boredom, they'll try to find something else to do.&lt;br&gt;
With a computer or phone at hand, a brain that fears being bored has plenty of opportunities to distract itself.&lt;/p&gt;

&lt;p&gt;There are times when being reactive is essential.&lt;br&gt;
If there's a fire to put out, be that login infrastructure suddenly offline or a literal fire in the building, you better be responsive.&lt;/p&gt;

&lt;p&gt;But if you react to every input, you'll never make progress on what truly matters to you.&lt;br&gt;
Whether it's your brain's need for entertainment or the stream of messages in your work chat, you should not let others dictate where you direct your attention.&lt;/p&gt;

&lt;p&gt;Processing your inboxes is a proactive approach.&lt;br&gt;
You still need to deal with whatever you'll find in there, but you give yourself the opportunity to do it strategically.&lt;/p&gt;




&lt;p&gt;Look at your inbox as a whole, and you'll identify the most important items to tackle—the ones that move the needle.&lt;br&gt;
When you continuously check your inbox, your day risks becoming a jumble of unfinished work, with each new entry setting you off in a different direction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open your inbox only when you have the time and mental bandwidth to address whatever you'll find in it, either by tackling it or by organizing it into your trusted system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't check.&lt;br&gt;
Process.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://giolodi.com/2023/08/dont-check-your-inbox-process-it/"&gt;giolodi.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover credits &lt;a href="https://unsplash.com/photos/jF-8LUJMrdk"&gt;Rinck Content Studio&lt;/a&gt;, with edits mine.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://mokagio.substack.com/"&gt;Subscribe here&lt;/a&gt; to receive new posts right in your inbox and access exclusive content.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>collaboration</category>
    </item>
    <item>
      <title>What does it mean to be a productive software developer?</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Fri, 08 Jul 2022 21:03:22 +0000</pubDate>
      <link>https://dev.to/mokagio/what-does-it-mean-to-be-a-productive-software-developer-5af</link>
      <guid>https://dev.to/mokagio/what-does-it-mean-to-be-a-productive-software-developer-5af</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a re-blog from &lt;a href="https://giolodi.com"&gt;giolodi.com&lt;/a&gt;. Checkout &lt;a href="https://giolodi.com/2022/07/what-does-it-mean-to-be-a-productive-software-developer/"&gt;the original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Productivity is often thought of as "getting things done."&lt;br&gt;
This definition is intuitive to grasp and makes it easy to measure productivity.&lt;br&gt;
But in the context of software development, and knowledge work at large, &lt;strong&gt;"getting things done" is a hopelessly short-sighted way to define productivity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A machine cranking widgets is as productive as the number of widgets it cranks.&lt;br&gt;
The widgets are all the same, so the more the machine can crank in a given time, the more productive it is.&lt;br&gt;
However, the tasks on a software developer's plate are not all equal.&lt;br&gt;
Someone could spend a whole day relentlessly ticking off tasks on their to-do list, but if those tasks are useless, the day will not have a productive one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Productive software developers don't merely get &lt;em&gt;things&lt;/em&gt; done. They get &lt;em&gt;impactful&lt;/em&gt; things done.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Productivity is tied to impact.&lt;br&gt;
It is a measure of results, not raw output.&lt;br&gt;
So, stop counting how many tickets you moved into the done column of your Jira board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impactful work is work that generates positive change in the business.&lt;/strong&gt;&lt;br&gt;
Yes, the business.&lt;br&gt;
As important as self-determination is, as crucial as it is to exert mastery and to find work that is inherently satisfying, we need to come to terms with the fact that productivity in the workplace depends on the effect we have on the bottom line.&lt;/p&gt;

&lt;p&gt;If software development is your hobby, then a productive session might just be one where you have fun, even if all you do is tinker with your &lt;code&gt;.vimrc&lt;/code&gt;.&lt;br&gt;
But if software development is your job, then you need to ask yourself whether you produced something valuable, and, as Derek Sivers put it, "money is a neutral indicator of value."&lt;/p&gt;

&lt;p&gt;Using impact as a lens to understand productivity, it becomes clear that cleaning up your inbox is not as productive as reviewing a colleague's pull request to unblock them.&lt;br&gt;
Likewise, fixing a bug that trims the last word in the last cell of your settings screen is not as important as fixing a bug that prevents users from signing up to your service.&lt;/p&gt;

&lt;p&gt;Impact, value delivered, is the true measure of a software developer's productivity.&lt;br&gt;
But impact doesn't exist in isolation.&lt;br&gt;
&lt;strong&gt;There is another crucial dimension of productivity, one that is too often left out of the conversation: time horizon&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Some activities might not seem productive in the context of a particular day, but do contribute to mid-to-long term productivity.&lt;/p&gt;

&lt;p&gt;Resting is the perfect example of how factoring in the time horizon changes the definition of productive activity.&lt;br&gt;
If you limit your view to impact over a given day, then the more work you can fit into it, the better.&lt;br&gt;
However, as anyone who went through burnout will tell you, overworking is not sustainable.&lt;br&gt;
Unless there's a fire to put out, there's no point "killing it" today if the result is you'll be out of commission for the rest of the week.&lt;br&gt;
An ongoing incident that is losing you money and customers grants burning the midnight oil, all the rest can wait till tomorrow.&lt;br&gt;
(&lt;em&gt;If you are in your twenties and think this example doesn't make any sense, trust this 33-year-old grump—Wait until you cross the 30-threshold, then you'll know what I'm talking about.&lt;/em&gt;)&lt;br&gt;
Getting plenty of rest in your day is productive because it ensures you can keep working without catastrophic burnout.&lt;/p&gt;

&lt;p&gt;Other activities that are productive in the long run include: reading to learn something new, paying off technical debt, and taking a few minutes at the end of the day to reflect on what went well and what you could have done better.&lt;/p&gt;




&lt;p&gt;Once you move beyond the myopic measure of raw output, productivity becomes too nuanced to fit a scorecard.&lt;br&gt;
Productivity is a function of impact over a medium-to-long time horizon, but that is hard to quantify without hindsight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To be a productive developer, the best you can do is to choose tasks to work on by factoring in business objectives, time horizon, and opportunity cost.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If that sounds hard, it's because it is.&lt;br&gt;
And ambiguous, too.&lt;/p&gt;

&lt;p&gt;You won't get it right all the time, but that's not the point.&lt;br&gt;
What matters is being intentional, thinking impact over the long-term, and error-correcting as you go.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This was a re-blog from &lt;a href="https://giolodi.com"&gt;giolodi.com&lt;/a&gt;. Checkout &lt;a href="https://giolodi.com/2022/07/what-does-it-mean-to-be-a-productive-software-developer/"&gt;the original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enjoyed this post? &lt;a href="https://buttondown.email/mokagio"&gt;Get new ones in your inbox&lt;/a&gt;&lt;/em&gt; 👉📬&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image is a remix of the author of &lt;a href="https://unsplash.com/photos/_an7SFyNHF0"&gt;this picture by Amr Taha&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>Why Teamwork Is In Your Best Self-Interest</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Mon, 04 Jul 2022 18:39:31 +0000</pubDate>
      <link>https://dev.to/mokagio/why-teamwork-is-in-your-best-self-interest-28b8</link>
      <guid>https://dev.to/mokagio/why-teamwork-is-in-your-best-self-interest-28b8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a re-blog from &lt;a href="https://giolodi.com/2022/07/why-teamwork-is-in-your-best-self-interest/"&gt;giolodi.com&lt;/a&gt;. Checkout the &lt;a href="https://giolodi.com/2022/07/why-teamwork-is-in-your-best-self-interest/"&gt;original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Knowledge work depends on teamwork. It sounds like a cliché, but it's objectively true that working with others s how we achieve better results than we could by ourselves. Our species transformed an inhospitable planet into a home where to thrive through various forms of collaboration and teamwork.&lt;/p&gt;

&lt;p&gt;Not everybody likes teamwork. Some people are introverts to the core and might struggle to make their voices heard. Others just want to show up, do their job, and go home, no question asked. You sometimes have a vision for how a project should evolve, but you can't execute it because the people around you "just don't get it." There are also folks that have yet to develop the emotional intelligence required to operate with others.&lt;/p&gt;

&lt;p&gt;Regardless of how you feel about teamwork, I want to make a case for you to &lt;em&gt;prioritize it&lt;/em&gt;. Teamwork is an essential part of "your work," not something to attend to once you ticked all the other tasks on your to-do list.&lt;/p&gt;

&lt;p&gt;Let's get specific. When I refer to teamwork in the context of software development, I'm thinking of all those activities that make other people move forward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code reviews&lt;/li&gt;
&lt;li&gt;Commenting on RFCs&lt;/li&gt;
&lt;li&gt;Brainstorming and planning meetings&lt;/li&gt;
&lt;li&gt;Pair programming session to work through gnarly code&lt;/li&gt;
&lt;li&gt;Reading your teammates status updates, in case there's something you can do to help&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the face of it, none of those activities help you with &lt;em&gt;your&lt;/em&gt; work. If you spend a day doing only those, you might appear behind. But that's a terribly short-sighted view of the matter. Because while it's true that your PR might still be in draft mode, everyone you helped made some progress. The whole team moved forward, likely more than if you had only worked on your task.&lt;/p&gt;

&lt;p&gt;One could object that if they always start by helping others, they'll never get to do their work. That's rarely the case because once you unblock someone, they won't immediately have new work for you to review. If you do really find yourself overwhelmed by teamwork tasks, you could adopt a prioritized rationed system: Work on the most important unblocking request, then on your most important task, then on the second most important unblocking request, and so on.&lt;/p&gt;

&lt;p&gt;Prioritizing teamwork activities might appear self-less, but you have much to gain from it yourself. Brownie points for a start. If you consistently help people, they'll be more likely to help you. On top of that, unblocking others will likely make your own job easier—assuming the work your team took on board is such that everyone operates towards a common goal, which is a topic for another day.&lt;/p&gt;

&lt;p&gt;Here's one more point that will convince even the most self-serving people: From the outside, a top performer in a poor-performing team looks like a poor performer or an average performer at best. &lt;strong&gt;In a top-performing team, everyone looks like a top-performer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want a raise, make your team better.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Photo credits &lt;a href="https://unsplash.com/photos/923_XGZsOlU"&gt;Bruno Emmanuelle&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This was a re-blog from &lt;a href="https://giolodi.com/2022/07/why-teamwork-is-in-your-best-self-interest/"&gt;giolodi.com&lt;/a&gt;. Checkout the &lt;a href="https://giolodi.com/2022/07/why-teamwork-is-in-your-best-self-interest/"&gt;original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>teamwork</category>
      <category>team</category>
      <category>management</category>
    </item>
    <item>
      <title>Three Tips To Get Started With Deep Work</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Wed, 20 Apr 2022 10:46:42 +0000</pubDate>
      <link>https://dev.to/mokagio/three-tips-to-get-started-with-deep-work-oag</link>
      <guid>https://dev.to/mokagio/three-tips-to-get-started-with-deep-work-oag</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a re-blog from &lt;a href="https://giolodi.com/2022/04/three-tips-to-get-started-with-deep-work/"&gt;giolodi.com&lt;/a&gt;. Checkout the &lt;a href="https://giolodi.com/2022/04/three-tips-to-get-started-with-deep-work/"&gt;original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;So you decided to try out this &lt;em&gt;deep work&lt;/em&gt; thing that everyone is talking about.&lt;br&gt;
You added a "Deep Work 🎧" event to your calendar from 10am to 12pm.&lt;br&gt;
Your caffeinated beverage of choice is at hand, your desk is clear, and there's a snack in the drawer, just in case.&lt;/p&gt;

&lt;p&gt;Now what?&lt;/p&gt;

&lt;p&gt;I have three tips for you, but let's get on the same page on what deep work is first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep work is focused, uninterrupted, single-tasked, specialized work.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cal Newport coined the term in the &lt;a href="https://geni.us/FITEF"&gt;book&lt;/a&gt; by the same name to identify certain high-value knowledge-work activities and how to best execute them.&lt;br&gt;
If you want to get serious in approaching your work, reading the whole of &lt;a href="https://geni.us/FITEF"&gt;&lt;em&gt;Deep Work&lt;/em&gt;&lt;/a&gt; is a great place to start.&lt;/p&gt;

&lt;p&gt;Now, on with the tips.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 1: Ease into it
&lt;/h2&gt;

&lt;p&gt;Achieving and maintaining intense focus is &lt;em&gt;hard&lt;/em&gt;.&lt;br&gt;
If you are new to deep work, it's best to start gradually.&lt;/p&gt;

&lt;p&gt;Aim for quality over quantity of focused time.&lt;/p&gt;

&lt;p&gt;That 2 hours block you put in your calendar might be too ambitious.&lt;br&gt;
Consider reducing it to a more realistic 30 minutes.&lt;br&gt;
The more sessions you put under your belt, the longer intervals you'll be able to reach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 2: Have a plan
&lt;/h2&gt;

&lt;p&gt;Decide what to work on &lt;em&gt;before&lt;/em&gt; starting your deep work session.&lt;/p&gt;

&lt;p&gt;Having a plan reduces the cognitive effort to get started.&lt;br&gt;
The brain has a natural tendency to conserve energy and, given a choice, will gravitate to more accessible but less meaningful work.&lt;br&gt;
You can bypass that temptation by separating the decision phase from the execution one.&lt;/p&gt;

&lt;p&gt;For example, you could start your day by &lt;a href="https://twitter.com/mokagio/status/1509770521554358274?s=20&amp;amp;t=3ypFwouXy8HPRNsUq2c5LQ"&gt;processing all inboxes&lt;/a&gt;, identifying the most valuable things to work on, and blocking out deep work time for those in your schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 3: Rest afterward
&lt;/h2&gt;

&lt;p&gt;When done right, deep work is cognitively draining.&lt;br&gt;
Your mind will need a rest after each session.&lt;/p&gt;

&lt;p&gt;Taking some time off will help you flush the attention residue from the task you worked on, consolidate the learnings you made, and replenish your mental energy to focus appropriately later.&lt;/p&gt;

&lt;p&gt;A good break should involve stepping away from your computer and getting your body moving to compensate for the time you have spent still.&lt;br&gt;
If your schedule is packed, at least take a walk down to the kitchen to get a glass of water.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus Tip: Quit Slack
&lt;/h2&gt;

&lt;p&gt;It should come without saying, but you cannot work deeply if you have Slack or any other instant messaging client open in the background.&lt;/p&gt;

&lt;p&gt;Deep work requires uninterrupted intense focus.&lt;br&gt;
Checking notifications during a session is in antithesis to the deep work definition.&lt;br&gt;
This is not only me being a stickler for semantics.&lt;br&gt;
Whether you like it or not, those boxes popping in the corner of your screen hijack your attention.&lt;br&gt;
That hampers your ability to direct as much focus as you can to the task at hand.&lt;/p&gt;




&lt;p&gt;Working deeply is both a skill and a habit. As such, it needs to be established and trained.&lt;/p&gt;

&lt;p&gt;If you're starting out, don't be surprised or discouraged if it's hard: It's supposed to be!&lt;/p&gt;

&lt;p&gt;To make it easier on yourself, aim for quality over quantity in the length of your session, have a plan for what to work on, and make sure to recharge afterward.&lt;/p&gt;

&lt;p&gt;Keep at it day after day.&lt;br&gt;
The real value of deep work is not in what you get done in a single session but in the compound results that emerge from stringing together session after session.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This was a re-blog from &lt;a href="https://giolodi.com/2022/04/three-tips-to-get-started-with-deep-work/"&gt;giolodi.com&lt;/a&gt;. Checkout the &lt;a href="https://giolodi.com/2022/04/three-tips-to-get-started-with-deep-work/"&gt;original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enjoyed this post? &lt;a href="https://buttondown.email/mokagio"&gt;Get new ones in your inbox 👉📬&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image credits: &lt;a href="https://unsplash.com/@wocintechchat?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Christina @ wocintechchat.com&lt;/a&gt; via &lt;a href="https://unsplash.com/s/photos/deep-work?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>deepwork</category>
      <category>productivity</category>
      <category>timemanagement</category>
    </item>
    <item>
      <title>How To Cut Through The Crypto Noise</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Sun, 17 Apr 2022 20:48:44 +0000</pubDate>
      <link>https://dev.to/mokagio/how-to-cut-through-the-crypto-noise-cde</link>
      <guid>https://dev.to/mokagio/how-to-cut-through-the-crypto-noise-cde</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a re-blog from [giolodi.com](&lt;a href="https://giolodi.com/2022/04/how-to-cut-through-the-crypto-noise/"&gt;https://giolodi.com/2022/04/how-to-cut-through-the-crypto-noise/&lt;/a&gt;. Checkout &lt;a href="https://giolodi.com/2022/04/how-to-cut-through-the-crypto-noise/"&gt;the original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Will we soon be paying for &lt;a href="https://giolodi.com/2022/04/books-vs-breakfasts/"&gt;breakfast&lt;/a&gt; in Bitcoin, using dollar notes as Monopoly money, or are we on the verge of a bubble that's about to explode?&lt;/p&gt;

&lt;p&gt;I've never bought any crypto, but the more time passes, the more I'm experiencing FOMO. Is this my rational brain sensing something promising ahead, or my emotional brain scared of not doing what everyone else seems to be doing?&lt;/p&gt;

&lt;p&gt;It's tough to form an opinion on cryptocurrencies. There's a lot of noise in the discourse online, and it's challenging to find trusted sources. Many big names in tech promote crypto. But are they genuine, or are they playing a speculation game? Basically, doing PR for whatever coin or startup they just invested in?&lt;/p&gt;

&lt;p&gt;In a case like this, it helps to apply a &lt;a href="https://en.wikipedia.org/wiki/Dialectic"&gt;dialectic&lt;/a&gt; inspired process. Take some of the best arguments in favor and against a topic and clash them. Look for contradictions and ideas that stand on their own feet, regardless of which side brought them forward.&lt;/p&gt;

&lt;p&gt;An argument against crypto I came across recently is &lt;a href="https://www.nytimes.com/2022/04/05/opinion/ezra-klein-podcast-dan-olson.html"&gt;Ezra Klein's interview with Dan Olsen&lt;/a&gt; about the topics of his video essay &lt;a href="https://www.youtube.com/watch?v=YQ_xWvX1n9g"&gt;Line Goes Up&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the other end of the spectrum, &lt;a href="https://twitter.com/balajis"&gt;Balaji Srinivasan&lt;/a&gt; is one of the most articulate defenders of crypto and Web3. His &lt;a href="https://fs.blog/knowledge-project-podcast/balaji-srinivasan-2/"&gt;interview on The Knowledge Project podcast&lt;/a&gt; is a good place to start.&lt;/p&gt;

&lt;p&gt;Finally, &lt;a href="https://nav.al/vitalik"&gt;this conversation&lt;/a&gt; with Ethereum's creator &lt;a href="https://twitter.com/VitalikButerin"&gt;Vitalik Buterin&lt;/a&gt; and investors &lt;a href="https://twitter.com/naval"&gt;Naval Ravikant&lt;/a&gt; and &lt;a href="https://twitter.com/dragonfly_cap"&gt;Haseeb Qureshi&lt;/a&gt; dives into interesting technical details.&lt;/p&gt;

&lt;p&gt;I won't tell you where I stand after listening to those podcasts. The whole point of the exercise is for one to form their own opinion.&lt;/p&gt;

&lt;p&gt;If you want to chat more about crypto (or anything else), get in touch &lt;a href="https://twitter.com/mokagio"&gt;on Twitter&lt;/a&gt;. And if you have similar well-thought, high-signal conversations to recommend, please send them my way. There's always more to learn.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This was a re-blog from [giolodi.com](&lt;a href="https://giolodi.com/2022/04/how-to-cut-through-the-crypto-noise/"&gt;https://giolodi.com/2022/04/how-to-cut-through-the-crypto-noise/&lt;/a&gt;. Checkout &lt;a href="https://giolodi.com/2022/04/how-to-cut-through-the-crypto-noise/"&gt;the original&lt;/a&gt; for more links and posts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enjoyed this post? &lt;a href="https://buttondown.email/mokagio"&gt;Get new ones in your inbox 👉📬&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo credits: &lt;a href="https://unsplash.com/@kanchanara?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Kanchanara&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;. Modified by the author.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>How to merge pull requests with a commit that improves your Git history</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Wed, 25 Nov 2020 13:13:45 +0000</pubDate>
      <link>https://dev.to/mokagio/how-to-merge-pull-requests-with-a-commit-that-improves-your-git-history-211c</link>
      <guid>https://dev.to/mokagio/how-to-merge-pull-requests-with-a-commit-that-improves-your-git-history-211c</guid>
      <description>&lt;p&gt;When you "Squash and merge" a pull request on GitHub, the merge commit title defaults to the PR title.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using the pull request title, or any descriptive title with the PR id, makes a massive difference in how readable your Git history is.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wish GitHub had the same behavior for "Merge pull request" instead, it uses Git's default merge title "&lt;code&gt;Merge pull request #123 from username/branch-name&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;Luckily, it takes just a few seconds to copy the PR title into the merge commit field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lnmayGYU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/mokacoding/2020-11-19-github-merge-title.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lnmayGYU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/mokacoding/2020-11-19-github-merge-title.gif" alt="GIF showing how to copy-paste the pull request title into the merge commit title field"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Is the effort worth it? You bet!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before we continue, an obvious solution to the problem would be to "Squash and merge" all PRs instead. Obvious, yes, but sometimes not desirable and other times not possible because of established team conventions. This post doesn't want to be an argument for merging vs. squashing.&lt;br&gt;
The idea of keeping a clear and informative Git history is valid regardless of how we get our changes into it.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why does the merge commit title matter?
&lt;/h2&gt;

&lt;p&gt;Imagine someone offered you a million dollars if you can guess what the latest commit on a repository does by only reading its title. Would you rather the commit title was this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Merge pull request #123 from add-author-label
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add author label to blogpost description view (#123)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously, no one will ever ask you to guess what a commit does only by reading its title – let alone offer you a million dollars. Still, understanding what code does and working with it is something you are being paid for. The easier you can do that the more value you can bring to the table.&lt;/p&gt;

&lt;p&gt;It's true that the GitHub UI makes it easy to bring up extra information for a commit, as well as the PR it belongs to. Even though the extra information is only one click away, the second commit is more explicit than the first. There is less friction for the reader to understand what the commit does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shorten the path to understanding
&lt;/h2&gt;

&lt;p&gt;Software developers appreciate the value of clean, readable code. Clean code is easy to follow, making it easy to understand and, in turn, easy to work with.&lt;/p&gt;

&lt;p&gt;Clean code is what every programmer opening an unfamiliar codebase hopes to find. The cleaner the code, the less time it will take to get up to speed and be productive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The productivity advantages of &lt;a href="https://mokacoding.com/blog/pipe-wrench/"&gt;clarity&lt;/a&gt; apply to Git commits as well as code.&lt;/strong&gt; If you can shorten the path to understanding your Git history, every developer who will read it will benefit from it – including your future self.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn your Git log into a readable story
&lt;/h2&gt;

&lt;p&gt;Consistently using descriptive titles for your merge commits will turn your Git log messages into a human-readable history of the changes that made it into the codebase.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;git log&lt;/code&gt; command has an option called &lt;code&gt;--first-parents&lt;/code&gt; to follow only the first parent commit upon seeing a merge commit. When applied to the log on the main branch of a repository, where all the PRs get merged, the result is a list of merge commits only.&lt;/p&gt;

&lt;p&gt;Compare the output when using a descriptive title to the PR merge commit vs. the default one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git log --pretty=oneline --abbrev-commit --first-parent

a2055b7 (HEAD -&amp;gt; trunk, origin/trunk) Merge pull request #4 from mokagio/feature-author-label
64344e0 Merge pull request #3 from mokagio/improve-mobile-layout
70ba8ac Merge pull request #2 from mokagio/feature-more-negative-space
7d5c9da Merge pull request #1 from mokagio/feature-dark-mode-css-support
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log --pretty=oneline --abbrev-commit --first-parent

a2055b7 (HEAD -&amp;gt; trunk, origin/trunk) Add author label to post metadata component (#4)
64344e0 Improve layout on mobile devices (#3)
70ba8ac Use more negative space (#2)
7d5c9da Support dark mode via CSS media query (#1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second log reads like a story. The first has little information to offer other than the fact that stuff got merge in this branch.&lt;/p&gt;

&lt;p&gt;When you pull the latest changes from your main branch, you can run this filtered &lt;code&gt;git log&lt;/code&gt; to get an idea of the recent changes. &lt;em&gt;Tip&lt;/em&gt;: define &lt;a href="https://mokacoding.com/blog/terminal-aliases/"&gt;an alias for it&lt;/a&gt; to make it easier to call it; mine is &lt;code&gt;glgf&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Using a descriptive title when you merge your pull requests on GitHub is a process that adds friction in the short run to remove friction in the long run.&lt;/p&gt;

&lt;p&gt;It takes longer to merge a PR when you need to copy its tile or come up with a succinct one for the commit. Those extra seconds, a couple of minutes in the worse scenario, will pay off because every time a developer will look at the history, they'll benefit from its greater clarity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The asymmetry between the one time cost of crafting the merge and the many times people will read the history makes the tradeoff all the more worth it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, next time you're about to click that merge button, spend a few extra seconds to add a descriptive title. Your team, the users of your open source software, your future self, they'll all thank you for it.&lt;/p&gt;

&lt;p&gt;What do you think of this approach? What are your best practices for effective GitHub pull requests and tidy Git history? I'd love to hear from you! Leave a comment below or get in touch on Twitter at &lt;a href="https://twitter.com/mokagio"&gt;@mokagio&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
    </item>
    <item>
      <title>How to make the View to ViewModel relationship clear in SwiftUI</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Thu, 05 Nov 2020 09:37:31 +0000</pubDate>
      <link>https://dev.to/mokagio/how-to-make-the-view-to-viewmodel-relationship-clear-in-swiftui-1om</link>
      <guid>https://dev.to/mokagio/how-to-make-the-view-to-viewmodel-relationship-clear-in-swiftui-1om</guid>
      <description>&lt;p&gt;SwiftUI lends itself well to be used together with the Model-View-ViewModel (MVVM) pattern. You can keep the view lean by moving all of the presentation logic and behavior into a view model with little to no code to sync between the two, thanks to framework tools like &lt;code&gt;@ObservedObject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While, in theory, you could have a view model power different views, like a row in a list as well as a detail screen, in practice, there is usually a 1-to-1 relationship between a view and its view model.&lt;/p&gt;

&lt;p&gt;To make this connection clearer, we can use a Swift language feature called &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/NestedTypes.html"&gt;&lt;em&gt;nested types&lt;/em&gt;&lt;/a&gt;. We can define the view model as a type &lt;em&gt;within&lt;/em&gt; the view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nested Type View Model
&lt;/h2&gt;

&lt;p&gt;Nested types allow us to "nest supporting enumerations, classes, and structures within the definition of the type they support."&lt;/p&gt;

&lt;p&gt;When there is a 1-to-1 relationship between a view and view model, when the view model supports a single view, a nested type is a great way to make that relationship explicit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BookDetail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;@ObservedObject&lt;/span&gt; &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ViewModel&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;BookDetail&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find a working example of this code in action &lt;a href="https://github.com/mokagio/ReadingList"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to the nested type, the full name of the view model is &lt;code&gt;BookDetail.ViewModel&lt;/code&gt;. This makes it obvious at a semantic level that the view model is related to &lt;code&gt;BookDetail&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You could argue that &lt;code&gt;BookDetail.ViewModel&lt;/code&gt; is not that different from &lt;code&gt;BookDetailViewModel&lt;/code&gt;. Plus, since Xcode has fuzzy auto-completion – &lt;em&gt;when it works, that is&lt;/em&gt; – there is no difference when typing the two.&lt;/p&gt;

&lt;p&gt;While that's all true, this approach has some advantages compared to keeping the two concepts in unrelated types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages — Clearer and less error-prone
&lt;/h2&gt;

&lt;p&gt;First of all, it's worth reiterating that using a nested type makes the relationship between the two types more evident than merely relying on their names. I feel this modeling expresses the design at &lt;a href="https://mokacoding.com/blog/pipe-wrench/"&gt;a more precise level&lt;/a&gt;, making it easier to understand the code.&lt;/p&gt;

&lt;p&gt;Within the view definition, we can reference the view model just as &lt;code&gt;ViewModel&lt;/code&gt;, which leaves the code more compact.&lt;/p&gt;

&lt;p&gt;The nested type also makes refactoring simpler.&lt;br&gt;
If we ever need to rename the view, we won't need to touch the &lt;code&gt;ViewModel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's impossible for the names of the two types to diverge.&lt;br&gt;
We can't forget to update the view model after updating the view because there is no update to make on it; we'll never have a &lt;code&gt;BookDetail&lt;/code&gt; view using a &lt;code&gt;BookInfoViewModel.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the same way, there is no chance to make a typo in the root of the view model type name – one can still mistype &lt;code&gt;ViewModel&lt;/code&gt;, though.&lt;/p&gt;

&lt;p&gt;As much as I like the purity of this approach, it comes with a downside that it's hard to look past: it makes it harder to find the view model code with Open Quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  One disadvantage with Open Quickly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://xcodetips.com/tips/shift-cmd-o-open-quickly.html"&gt;Open Quickly&lt;/a&gt; is an Xcode feature that allows you to fuzzy find files and types by typing their name. Press &lt;code&gt;Shift Cmd O&lt;/code&gt;, and a search field will appear on screen. As you type your query, Xcode will show the results.&lt;/p&gt;

&lt;p&gt;In the case of nested type view models, there is no query, fuzzy or not, that can easily bring up the right type.&lt;/p&gt;

&lt;p&gt;For example, "bookdet" will show the &lt;code&gt;BookDetail.swift&lt;/code&gt; file, but there's no mention of the view model class. If we jump to that file, we'll have to find the class by scrolling or with &lt;code&gt;Cmd F&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HYqGaht0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/mokacoding/2020-11-04-bookdet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HYqGaht0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/mokacoding/2020-11-04-bookdet.png" alt='Screenshot of the Open Quickly window with the "bookdet" query but no view model result'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Searching for "bookdetailviewmodel" brings up no results, despite the query being more explicit. "viewmodel" returns all the view model classes, and you need to read the little file name field on each line to identify the right one.&lt;/p&gt;

&lt;p&gt;The only solution I found is to &lt;strong&gt;keep the view models in dedicated files&lt;/strong&gt;. If you do that, then a fuzzy query like "bdvm" will bring up &lt;code&gt;BookDetail.ViewModel.swift&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8fVbacgM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/mokacoding/2020-11-04-bdvm-working.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8fVbacgM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/mokacoding/2020-11-04-bdvm-working.png" alt='Screenshot of the Open Quickly window with the "bdvm" query and the matching MVVM view model file'&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Extracting the view models in dedicated files is something you'd probably want to do anyways to keep the domains separated and avoid the chance of merge conflicts when two developers are working on the view and the view model in parallel on different branches. Still, it's annoying to &lt;em&gt;have to&lt;/em&gt; do it to find the objects efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yay or Nay?
&lt;/h2&gt;

&lt;p&gt;None of the advantages of using nested types for view models are life-changing. This approach won't make your app better from a functionality point of view, nor will it save you time or reduce the chance of making mistakes. It's all &lt;em&gt;syntax sugar&lt;/em&gt;, at best.&lt;/p&gt;

&lt;p&gt;Is the smarter looking code worth it, or is it better to do a bit more typing and trust the devs in the team will still get the 1-to-1 relationship based on the name of the types, and that code review will catch the cases in which the two diverge?&lt;/p&gt;

&lt;p&gt;I haven't had the chance to use this pattern on a team in the real world, so I can't answer that for sure. I just found this approach fascinating and wanted to share it with you.&lt;/p&gt;

&lt;p&gt;What do you think? I'd love to hear from you! Leave a comment below or get in touch on Twitter at &lt;a href="https://twitter.com/mokagio"&gt;@mokagio&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>swiftui</category>
    </item>
    <item>
      <title>Dependency Injection in SwiftUI</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Thu, 29 Oct 2020 11:03:05 +0000</pubDate>
      <link>https://dev.to/mokagio/dependency-injection-in-swiftui-5c7f</link>
      <guid>https://dev.to/mokagio/dependency-injection-in-swiftui-5c7f</guid>
      <description>&lt;p&gt;There are different ways to do dependency injection in SwiftUI. In this post, we'll look at two of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the &lt;code&gt;@EnvironmentObject&lt;/code&gt; property wrapper&lt;/li&gt;
&lt;li&gt;Using a View Model Factory&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dependency Injection
&lt;/h3&gt;

&lt;p&gt;Dependency injection, DI for short, is the practice of providing an object with the other objects it depends on rather than creating them internally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Without dependency injection&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// With dependecy injection&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bar&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;DI makes the design more flexible, keeps your code &lt;a href="https://mokacoding.com/blog/honesty-oriented-programming/" rel="noopener noreferrer"&gt;honest&lt;/a&gt;, and, when paired with a protocol, allows you to test the object behavior by providing test doubles.&lt;/p&gt;

&lt;p&gt;The challenge with dependency injection is how to provide components with the dependencies they need without manually passing them through all of their ancestors in the hierarchy. &lt;code&gt;@EnvironmentObject&lt;/code&gt; and the View Model Factory both provide a clean solution to this.&lt;/p&gt;

&lt;p&gt;To compare these two approaches, let's imagine we're building a library reading list app. A tab view hosts two screens: one shows you all the books in the library, another your to-read list. You can select a title from the library list to see its details, then add it or remove it from your to-read list.&lt;/p&gt;

&lt;p&gt;The to-read list and book detail views both need access to the reading list storage; let's call it &lt;code&gt;ReadingListController&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Combine&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// By publishing the reading list, we can leverage SwiftUI to automatically&lt;/span&gt;
    &lt;span class="c1"&gt;// update the UI when a book is added or removed.&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// For the sake of this example, let's use in-memory storage. In the real&lt;/span&gt;
    &lt;span class="c1"&gt;// world, we'd be storing to disk and/or calling a remote API.&lt;/span&gt;
    &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;readingList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;isBookInList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's have a look at the two approaches to inject this dependency.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;@EnvironmentObject&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;SwiftUI offers the &lt;a href="https://developer.apple.com/documentation/swiftui/environmentobject" rel="noopener noreferrer"&gt;&lt;code&gt;@EnvironmentObject&lt;/code&gt; property wrapper&lt;/a&gt; to define "an observable object supplied by a parent or ancestor view." Every time the wrapped &lt;code&gt;ObservableObject&lt;/code&gt; emits a change, the framework will invalidate the view, resulting in a redraw.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@EnvironmentObject&lt;/code&gt; allows us to inject dependencies because it looks for its value in the SwiftUI environment. This means that a view deep in the hierarchy can access a dependency without its parent passing it through.&lt;/p&gt;

&lt;p&gt;The way to add the dependency into the environment is to call the [&lt;code&gt;environmentObject(_:)&lt;/code&gt;](&lt;a href="https://developer.apple.com/documentation/swiftui/view/environmentobject(_:%29)" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/swiftui/view/environmentobject(_:%29)&lt;/a&gt; method on any ancestor of the view that needs to access it. I find this is best done at the top level: in the &lt;code&gt;App&lt;/code&gt; implementation or in the &lt;code&gt;UIWindowSceneDelegate&lt;/code&gt; if you are mix-and-matching SwiftUI with UIKit.&lt;/p&gt;

&lt;p&gt;Let's look at some code; you can get the source for this example &lt;a href="https://github.com/mokagio/ReadingList/tree/trunk/PureSwiftUIExample" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;

&lt;span class="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ReadingListApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// The interface with the reading list storage.&lt;/span&gt;
    &lt;span class="c1"&gt;// This is the only place where we instantiate ReadingListController; no&lt;/span&gt;
    &lt;span class="c1"&gt;// singletons or static shared instances needed.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;readingListController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Scene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;WindowGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;TabView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;ToReadList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"To Read 📖"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tabItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"To Read"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;BookList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Books 📚"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tabItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All Books"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// Here we inject the ReadingListController instance in the&lt;/span&gt;
            &lt;span class="c1"&gt;// environment&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environmentObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The views that need access to &lt;code&gt;ReadingListController&lt;/code&gt; can get it via &lt;code&gt;@EnvironmentObject&lt;/code&gt;; the others don't have to know about it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BookList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Let's skip how to load the library books for the sake of brevity&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="c1"&gt;// BookList defines the view where to navigate when a row is&lt;/span&gt;
            &lt;span class="c1"&gt;// selected, but notice how it doesn't provide it with a reference&lt;/span&gt;
            &lt;span class="c1"&gt;// to a ReadingListController.&lt;/span&gt;
            &lt;span class="kt"&gt;NavigationLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BookDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BookDetail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;

    &lt;span class="c1"&gt;// Here, we access our injected dependency from the environment&lt;/span&gt;
    &lt;span class="kd"&gt;@EnvironmentObject&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isBookInList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Remove from reading list"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Add to reading list"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ToReadList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Here, too, we get our ReadingListController from the environment&lt;/span&gt;
    &lt;span class="kd"&gt;@EnvironmentObject&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readingList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The code above is tidy and easy to follow once you wrap your head around how &lt;code&gt;@EnvironmentObject&lt;/code&gt; works. Thanks to the SwiftUI framework internals, we don't have to write any code to keep the to-read list and book detail screens in sync; everything is taken care of for us.&lt;/p&gt;

&lt;p&gt;There's a catch, though, if you don't call &lt;code&gt;environmentObject&lt;/code&gt;, or if someone removes it by accident, the app will crash.&lt;/p&gt;

&lt;p&gt;The next approach removes the risk of runtime crashes.&lt;/p&gt;
&lt;h2&gt;
  
  
  View Models &amp;amp; View Model Factory
&lt;/h2&gt;

&lt;p&gt;If you use the MVVM pattern in SwiftUI, giving each view a view model containing all of the logic to present data and act on it, you can use it to inject dependencies by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moving the responsibility to build the views to show from the view layer to the view model;&lt;/li&gt;
&lt;li&gt;Passing the logic to build views in the view models at &lt;code&gt;init&lt;/code&gt; time; and&lt;/li&gt;
&lt;li&gt;Creating the view models in a centralized place, which can inject the dependency as part as the view-building logic in the &lt;code&gt;init&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Views should delegate all logic to their view models, be it what view to use as the destination of a &lt;code&gt;NavigationLink&lt;/code&gt; or what text to show in a button.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BookList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BookListViewModel&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="c1"&gt;// The view model tells the view what's the NavigationLink destination&lt;/span&gt;
            &lt;span class="kt"&gt;NavigationLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewForSelectedBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BookDetail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;@ObservedObject&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BookDetailViewModel&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;// The view models take care of actioning on the reading list.&lt;/span&gt;
            &lt;span class="c1"&gt;// Because of that, the view only need an instance of the view&lt;/span&gt;
            &lt;span class="c1"&gt;// model; the ReadingListController dependency is hidden inside it.&lt;/span&gt;
            &lt;span class="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addOrRemoveBook&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addOrRemoveButtonText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can find the code sample for this approach &lt;a href="https://github.com/mokagio/ReadingList/tree/trunk" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Notice how &lt;code&gt;BookDetail&lt;/code&gt; has no &lt;code&gt;if-else&lt;/code&gt; conditional now.&lt;br&gt;
The view is &lt;a href="https://martinfowler.com/eaaDev/uiArchs.html#HumbleView" rel="noopener noreferrer"&gt;&lt;em&gt;humble&lt;/em&gt;&lt;/a&gt;; it does what the view model tells it without any extra logic.&lt;/p&gt;

&lt;p&gt;The view models themselves don't know how to build views; they ask for that knowledge in the form of a closure at init time.&lt;br&gt;
Have a look at &lt;code&gt;BookListViewModel&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Combine&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;BookListViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;// When creating the view model, inject the logic to create the detail view&lt;/span&gt;
    &lt;span class="c1"&gt;// for a given book.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;viewForSelectedBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BookDetail&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;viewForSelectedBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BookDetail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;viewForSelectedBook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewForSelectedBook&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;BookDetailViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;addOrRemoveButtonText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readingListController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readingListController&lt;/span&gt;

        &lt;span class="c1"&gt;// This method is defined in a private extension below to DRY the code&lt;/span&gt;
        &lt;span class="c1"&gt;// without having to define a static function that could be accessed&lt;/span&gt;
        &lt;span class="c1"&gt;// here when self is not yet available.&lt;/span&gt;
        &lt;span class="n"&gt;addOrRemoveButtonText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;textForAddOrRemoveButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addOrRemoveBook&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isBookInList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;addOrRemoveButtonText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;textForAddOrRemoveButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;textForAddOrRemoveButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;isBookInList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"Remove from reading list"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Add to reading list"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The final piece of the puzzle is the actual injection of the &lt;code&gt;ReadingListController&lt;/code&gt; dependency from a centralized location. This object will be the only one instantiating &lt;code&gt;ReadingListController&lt;/code&gt; and will create the view models, passing the dependency to those that need it.&lt;/p&gt;

&lt;p&gt;A good name for an object whose sole purpose is to create other objects is &lt;em&gt;factory&lt;/em&gt;, a hint to the &lt;a href="https://en.wikipedia.org/wiki/Factory_method_pattern" rel="noopener noreferrer"&gt;factory pattern&lt;/a&gt;, although stripped of the functionality to let a class defer the instantiation of its components to its subclasses.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ViewModelFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Like when using the environment approach, ViewModelFactory is the only&lt;/span&gt;
    &lt;span class="c1"&gt;// point where we instantiate ReadingListController; no singletons or&lt;/span&gt;
    &lt;span class="c1"&gt;// static shared instances needed.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;readingListController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ReadingListController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Once again, let's gloss over how to load the books for the sake of&lt;/span&gt;
    &lt;span class="c1"&gt;// brevity.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeBookListViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BookListViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;BookListViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;viewForSelectedBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;unowned&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="kt"&gt;BookDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeBookDetailViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeBookDetailViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BookDetailViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;BookDetailViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeToReadListViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ToReadListViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;ToReadListViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;readingListController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This pattern removes the need to pass dependencies down each node of the hierarchy because &lt;code&gt;ViewModelFactory&lt;/code&gt; builds all of the view models and each view model receives the logic to construct the views at &lt;code&gt;init&lt;/code&gt; time.&lt;/p&gt;

&lt;p&gt;We can call &lt;code&gt;ViewModelFactory&lt;/code&gt; at the top level of our SwiftUI application, be it the &lt;code&gt;App&lt;/code&gt; or &lt;code&gt;UIWindowSceneDelegate&lt;/code&gt; implementation, to get the view models for the root views.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;

&lt;span class="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ReadingListApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;viewModelFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ViewModelFactory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Scene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;WindowGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;TabView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;ToReadList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;viewModelFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeToReadListViewModel&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"To Read 📖"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tabItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"To Read"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;BookList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;viewModelFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeBookListViewModel&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Books 📚"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tabItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All Books"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Pros &amp;amp; Cons
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@EnvironmentObject&lt;/code&gt; trades runtime-safety for conciseness and is a more text-book SwiftUI approach, but it can crash your app.&lt;/p&gt;

&lt;p&gt;Using view models for dependency injection requires a bit more work and conventions that developers need to respect but is safe at runtime.&lt;/p&gt;

&lt;p&gt;Writing some extra code when what you get in return is runtime safety seems like a reasonable tradeoff; that's the approach I prefer. I'm still new to SwiftUI, though, and often wonder how much of my thinking within the framework is impeded by the mindset and habits developed after years of working with UIKit.&lt;/p&gt;

&lt;p&gt;Which of these two ways do you prefer? Have you got other ways to inject dependencies in SwiftUI? I'd love to hear from you!&lt;br&gt;
Leave a comment below or get in touch on Twitter at &lt;a href="https://twitter.com/mokagio" rel="noopener noreferrer"&gt;@mokagio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a cross-post from my blog &lt;a href="https://mokacoding.com/blog/swiftui-dependency-injection/" rel="noopener noreferrer"&gt;mokacoding.com&lt;/a&gt;. Head over there for more content on Swift, testing, and productivity.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to Adam Campbell and &lt;a href="https://twitter.com/rpassis" rel="noopener noreferrer"&gt;Rogerio Paula Assis&lt;/a&gt; for reviewing an early draft of this post.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Related Posts
&lt;/h3&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95330%2Fb45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/how-to-test-view-controllers-navigation-3hhh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to test view controllers navigation&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Apr 17 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#swift&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ios&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95330%2Fb45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/test-doubles-in-swift-dummies-fakes-stubs-and-spies-2e9e" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Test Doubles in Swift: Dummies, Fakes, Stubs, and Spies.&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Feb 15 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#swift&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tdd&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95330%2Fb45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/ten-productivity-books-you-won-t-regret-reading-38bh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Ten Productivity Books You Won't Regret Reading&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Mar 27 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#books&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>swift</category>
      <category>swiftui</category>
    </item>
    <item>
      <title>Hyperfocus by Chris Bailey</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Tue, 13 Oct 2020 09:17:22 +0000</pubDate>
      <link>https://dev.to/mokagio/hyperfocus-by-chris-bailey-5bl7</link>
      <guid>https://dev.to/mokagio/hyperfocus-by-chris-bailey-5bl7</guid>
      <description>&lt;p&gt;&lt;a href="https://geni.us/R8avh"&gt;&lt;em&gt;Hyperfocus&lt;/em&gt;&lt;/a&gt; by &lt;a href="https://alifeofproductivity.com/"&gt;Chris Bailey&lt;/a&gt; is an easy read on the topics of productivity and creativity, a good entry-level book for any knowledge worker looking to use their brain to its full potential.&lt;/p&gt;

&lt;p&gt;The book, divided into two parts, covers first how to configure your environment and schedule to focus effectively, then how to foster creativity insights by taking productive breaks.&lt;br&gt;
It is a natural follow up to Chris' previous book &lt;a href="https://www.mokacoding.com/blog/the-productivity-project-notes/"&gt;&lt;em&gt;The Productivity Project&lt;/em&gt;&lt;/a&gt;, diving deeper into the topic of how to use your most crucial productivity tool: attention.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hyperfocus
&lt;/h2&gt;

&lt;p&gt;Hyperfocus, a term originating from &lt;a href="https://en.wikipedia.org/wiki/Hyperfocus"&gt;the ADHD literature&lt;/a&gt;, is the author's jargon for the process of managing your environment and schedule to minimize distraction and maximize the quality and duration of your attention.&lt;br&gt;
If you already read a few books on the topic, such as &lt;a href="https://geni.us/FITEF"&gt;&lt;em&gt;Deep Work&lt;/em&gt;&lt;/a&gt; or &lt;a href="https://www.mokacoding.com/blog/the-indistractable-developer/"&gt;&lt;em&gt;Indistractable&lt;/em&gt;&lt;/a&gt;, the framework and its suggestions will sound familiar.&lt;/p&gt;

&lt;p&gt;To practice hyperfocus:&lt;/p&gt;

&lt;p&gt;1. Choose a productive and meaningful target for your attention;&lt;br&gt;
2. Eliminate as many external and internal distractions as you can;&lt;br&gt;
3. Focus on that chosen object of attention; and&lt;br&gt;
4. Continually draw your focus back to that one object&lt;/p&gt;

&lt;p&gt;The final point is the one less touched upon by other productivity books, and the one Chris Bailey does an excellent job at unpacking.&lt;/p&gt;

&lt;p&gt;Monitoring where your attention is at and nudge it back on track when it wanders off is fundamental to achieving peak focus levels.&lt;br&gt;
Our minds are built for distraction.&lt;br&gt;
Reading, writing, coding... those are all activities that hijack parts of our brain to do something they didn't evolve for.&lt;br&gt;
Don't beat yourself up when your mind loses concentration while trying to solve a complex problem; gently steer it back on track.&lt;/p&gt;

&lt;p&gt;Hyperfocus is a framework to get the most out of your brain when working on challenging problems, but not everything a knowledge worker requires this kind of laser-focused attention.&lt;/p&gt;

&lt;p&gt;Tasks that require more creativity or long term vision are better executed when the mind has space to wander.&lt;br&gt;
The trick here is to give your attention a leash long enough to jump around and make unexpected connections but short enough that it won't get lost in the woods.&lt;br&gt;
Chris calls this process &lt;em&gt;scatterfocus&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Scatterfocus
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;While hyperfocus involves directing your attention outward, scatterfocus is about directing it inward, inside your own mind.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To practice scatterfocus, take a break from your computer and engage in something habitual and relaxing, like going for a walk, having a coffee out, or sorting the laundry (I find that relaxing,  okay? Don't judge).&lt;br&gt;
While doing so, let your mind wander, following where it goes without trying to steer it.&lt;br&gt;
Make sure to have a pen and paper at hand to note down the ideas that surface this way.&lt;/p&gt;

&lt;p&gt;Chris defines three particular modes to scatterfocus.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capture mode&lt;/li&gt;
&lt;li&gt;Problem-crunching mode&lt;/li&gt;
&lt;li&gt;Habitual mode&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Capture mode
&lt;/h3&gt;

&lt;p&gt;Capture mode is similar to the mind-sweep practice that David Allen defines in his &lt;a href="https://geni.us/m6O7"&gt;&lt;em&gt;Getting Things Done&lt;/em&gt;&lt;/a&gt; framework.&lt;br&gt;
Simply sit down and dump everything that's on your mind.&lt;br&gt;
This might seem awkward at first, but you'll see that tasks and worries will start to pour out on the paper once you get started.&lt;/p&gt;

&lt;p&gt;Scatterfocus in capture mode is an excellent remedy to the feeling of being overwhelmed.&lt;br&gt;
Get stuff off your head and into a medium on which you can organize them and plan how to tackle them.&lt;br&gt;
I find this is best paired with a hot drink at a cafe or at home with some instrumental music.&lt;/p&gt;
&lt;h3&gt;
  
  
  Problem-crunching mode
&lt;/h3&gt;

&lt;p&gt;When you are stuck on a problem, the problem-crunching scatterfocus mode will help you find the answer.&lt;br&gt;
You probably experienced this already: you're out on lunch break when suddenly the solution to the problem you struggled with all morning materializes in front of you.&lt;br&gt;
This mode is the intentional deployment of the same mechanism that resulted in that eureka moment.&lt;/p&gt;

&lt;p&gt;The mind-wandering in problem-crunching mode is more constrained than in the other modes.&lt;br&gt;
When you notice you're thinking about something unrelated to your problem, nudge your attention back to it.&lt;/p&gt;

&lt;p&gt;Cal Newport proposes a similar technique in &lt;a href="https://geni.us/FITEF"&gt;&lt;em&gt;Deep Work&lt;/em&gt;&lt;/a&gt;, calling it productive meditation.&lt;br&gt;
Take a time when you are occupied physically but not mentally, like walking, exercising, or driving, and focus on a well-defined professional problem.&lt;br&gt;
The main benefit of this practice, he argues, is in training your ability to focus intensely on a single problem.&lt;/p&gt;
&lt;h3&gt;
  
  
  Habitual mode
&lt;/h3&gt;

&lt;p&gt;Finally, habitual scatterfocus is the practice of letting your mind wander freely and see where it ends up.&lt;br&gt;
This is Chris' favorite mode and the one he recommends the most.&lt;br&gt;
Through this process, your mind will end up making unexpected connections and generating insights, new ideas, and plans for the future.&lt;/p&gt;

&lt;p&gt;When done right, habitual scatterfocus can also boost your mood and better recharge you.&lt;/p&gt;



&lt;p&gt;Intention and awareness are the two underlying themes in &lt;a href="https://geni.us/R8avh"&gt;&lt;em&gt;Hyperfocus&lt;/em&gt;&lt;/a&gt; and Chris Bailey's productivity approach.&lt;/p&gt;

&lt;p&gt;The foundation on which all the book's techniques stand is the idea that we cannot live in autopilot, but ought to take charge and make the most of our limited time and attention.&lt;br&gt;
Hyperfocus and scatterfocus might be unnecessary names for tactics that are neither new nor revolutionary, but they are nevertheless worth exploring and practicing.&lt;/p&gt;

&lt;p&gt;Scatterfocus, in particular, is my stand-out concept from the book.&lt;br&gt;
Not only it gives clear and practical instructions on how to take productive breaks,  but it also makes a case for the value of stepping away from your computer.&lt;br&gt;
If you are anything like me, this is something you need a constant reminder of.&lt;/p&gt;

&lt;p&gt;Get in touch on Twitter at &lt;a href="https://twitter.com/mokagio"&gt;@mokagio&lt;/a&gt; or leave a comment below to discuss hyper- and scatterfocus or anything else productivity-related.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a crosspost from my blog, &lt;a href="http://www.mokacoding.com/blog/hyperfocus-review/"&gt;mokacoding.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6vNuVRNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--20YcS3et--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/95330/b45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/clutter-is-costly--optimization-matters-51ea" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Clutter is costly &amp;amp; Optimization matters&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Feb 28 '19 ・ 5 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#books&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#softwaredesign&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6vNuVRNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--20YcS3et--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/95330/b45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/ten-productivity-books-you-won-t-regret-reading-38bh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Ten Productivity Books You Won't Regret Reading&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Mar 27 '19 ・ 6 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#books&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6vNuVRNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--20YcS3et--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/95330/b45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/how-to-become-an-indistractable-developer-3f9f" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How To Become An Indistractable Developer&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Jun  4 ・ 9 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#books&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>productivity</category>
      <category>books</category>
    </item>
    <item>
      <title>How To Become An Indistractable Developer</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Thu, 04 Jun 2020 11:46:46 +0000</pubDate>
      <link>https://dev.to/mokagio/how-to-become-an-indistractable-developer-3f9f</link>
      <guid>https://dev.to/mokagio/how-to-become-an-indistractable-developer-3f9f</guid>
      <description>&lt;p&gt;Have you ever gotten to the end of a workday exhausted but at the same time feeling like you didn't accomplish anything?
You went through a lot of tasks, had a lot of conversations, yet there's little to show for.
Where did all that time go?
Frustrating, isn't it?&lt;/p&gt;
&lt;p&gt;The thing is, feeling like you haven't gotten anything meaningful done is not just frustrating; it could also be dangerous for your career.&lt;/p&gt;
&lt;p&gt;More and more tech companies clearly state that they measure their employees' performance based on the impact they have on the business.
The &lt;a href="https://jobs.netflix.com/culture" rel="noopener noreferrer"&gt;Netflix culture memo&lt;/a&gt; has a section on impact: "You accomplish amazing amounts of important work.
You demonstrate consistently strong performance so colleagues can rely upon you."
"It's not a ladder like it is at the banks –instead, you're measured by what you've done, by taking on a larger scope, and by the real impact of your daily work," says the &lt;a href="https://www.facebook.com/careers/life/why-your-career-wont-plateau-at-facebook" rel="noopener noreferrer"&gt;Facebook careers page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Impact is directly proportional to your value with your employer and in the market.
Many external factors affect the impact, such as being in a good team, a manager that "gets you," a personal life that doesn't get in the way of work.
There is something entirely within our control, though, and that is the quality of our work.&lt;/p&gt;
&lt;p&gt;The quality of our work is directly proportional to our impact.
Therefore, the quality of our work is directly proportional to our value in the market.&lt;/p&gt;
&lt;p&gt;Even if the project you are working on seems like a lost cause, you won't regret delivering to the best of your ability.
You may actually increase its chances to succeed and show your team what you can do.
It's still a learning opportunity.
If none of that applies, at least you'll get it done faster and move on sooner.&lt;/p&gt;
&lt;p&gt;How can we raise the quality bar of our work?
In his book &lt;a href="https://geni.us/FITEF" rel="noopener noreferrer"&gt;Deep Work&lt;/a&gt;, &lt;a href="https://www.calnewport.com/" rel="noopener noreferrer"&gt;Cal Newport&lt;/a&gt; proposes this law of productivity:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;High-Quality Work Produced = (Time Spent) x (Intensity of Focus)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To produce quality work, you need to spend time working in a state of intense focus.
"Programmers need long uninterrupted periods of focus time," goes the adage.&lt;/p&gt;
&lt;p&gt;One way to increase both the time you spend focused and its intensity is to follow the model proposed by &lt;a href="https://www.nirandfar.com/" rel="noopener noreferrer"&gt;Nir Eyal&lt;/a&gt; in his book &lt;a href="https://geni.us/ayNk" rel="noopener noreferrer"&gt;Indistractable&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="indistractable"&gt;Indistractable&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;To be Indistractable means to be able to do what you set out to do while avoiding those things that pull you away from your goals.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmokacoding.s3.amazonaws.com%2F2020-05-27-indistractable.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmokacoding.s3.amazonaws.com%2F2020-05-27-indistractable.jpg" alt="Visual representation of the Indistractable model by Nir Eyal"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image sourced from &lt;a href="https://onezero.medium.com/being-indistractable-will-be-the-skill-of-the-future-a07780cf36f4" rel="noopener noreferrer"&gt;this post&lt;/a&gt; by the author.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;"Traction" are those activities that move you forward towards your objective, while distractions are those that pull you away.&lt;/p&gt;
&lt;p&gt;The arrows in the model show how both external and internal triggers, which we'll talk about shortly, affect both distraction &lt;em&gt;and&lt;/em&gt; traction.
To maximize traction, one needs to channel as much energy as possible in the arrows that go towards it.
To spend long uninterrupted time producing quality work, we need to tame both internal and external triggers so that they help with focus, not distraction.&lt;/p&gt;
&lt;p&gt;Let's look at the four areas of the model individually, starting from the more practical ones.&lt;/p&gt;
&lt;h3 id="make-time-for-traction"&gt;Make Time for Traction&lt;/h3&gt;
&lt;p&gt;If you want to prioritize something in life, you'll have to be intentional.
You'll need to make time for it.
When it comes to making time for focus, your calendar is your best friend.&lt;/p&gt;
&lt;p&gt;Eyal suggests to &lt;em&gt;timebox&lt;/em&gt; your schedule. That is, meticulously allocate time in your calendar for all the tasks in your day, then do your best to stick to your plan.&lt;/p&gt;
&lt;p&gt;"Keeping a timeboxed schedule is the only way to know if you are distracted; if you're not spending your time doing what you'd planned, you're off-track."&lt;/p&gt;
&lt;p&gt;At the start of the day, or even better at the end of the previous one, look ahead and plan how you'll spend your time.
Ideally, your schedule should reflect your priorities.
If you want to make progress on your coding tasks, there should be a big block of time dedicated to them.
But don't stop at just scheduling your work time, schedule your distractions as well.&lt;/p&gt;
&lt;p&gt;I've found having predefined times in my calendar where to be distracted to be an excellent cure for &lt;a href="https://en.wikipedia.org/wiki/Fear_of_missing_out" rel="noopener noreferrer"&gt;FOMO&lt;/a&gt;.
For example, checking the Slacks of the communities I'm part of once a day is often enough to be on top of what's happening there.
The same goes for texts and emails.&lt;/p&gt;
&lt;p&gt;Being a bit slower in responding to texts will make little difference in your social life, but it will make a huge difference in the quality and length of your focus time.
To be safe, you can always let the important people in your life know that if they need to reach you urgently, they should call, not text.&lt;/p&gt;
&lt;p&gt;Laura Vanderkam wrote extensively about the power of scheduling in her books &lt;a href="https://geni.us/kHdO" rel="noopener noreferrer"&gt;168 Hours: You Have More Time Than You Think&lt;/a&gt; and &lt;a href="https://geni.us/QwzQ" rel="noopener noreferrer"&gt;I Know How She Does It&lt;/a&gt;.
Check them out if you want to learn how to build a successful schedule and how to start tracking your time to understand how to make the most of it.&lt;/p&gt;
&lt;p&gt;Finally, you should schedule time in your calendar to review how you schedule time in your calendar.
This meta task is a way to verify that you have been consistent with your priorities and to discover the sources of distraction that pulled you away from focus.&lt;/p&gt;
&lt;h3 id="hack-back-external-triggers"&gt;Hack Back External Triggers&lt;/h3&gt;
&lt;p&gt;External triggers are those interruptions coming from the outside world.
The colleague tapping on your shoulder, the push notification on your phone, the new message in the group chat.&lt;/p&gt;
&lt;p&gt;It might seem like we don't have any control over those interruptions, but, to a degree, we do.&lt;/p&gt;
&lt;p&gt;Here are a few ways to fight off external distractions that software developers often face:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can avoid colleagues interrupting your work in the office by implementing the &lt;a href="https://www.rahulpnath.com/blog/the-headphones-rule/" rel="noopener noreferrer"&gt;headphones rule&lt;/a&gt;, or, even better, by working from home or a library if your workplace allows it when you need to be Indistractable.&lt;/li&gt;
&lt;li&gt;You can avoid notifications distracting you on your phone and computer by enabling Do Not Disturb. The cool thing about Do Not Disturb is that you can configure it to let apps with notifications you cannot afford to miss go through.&lt;/li&gt;
&lt;li&gt;Put your phone where you cannot see it.&lt;/li&gt;
&lt;li&gt;Install a &lt;a href="https://freedom.to/blog/8-website-blockers-for-studying-productivity-focus/" rel="noopener noreferrer"&gt;browser extension&lt;/a&gt; to block social media and other distracting sites you open on auto-pilot.&lt;/li&gt;
&lt;li&gt;Constantly work to keep your builds, tests, and other feedback loops as fast as possible, so that you won't be tempted to do something else while they run.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="master-internal-triggers"&gt;Master Internal Triggers&lt;/h3&gt;
&lt;p&gt;Whereas external triggers are those distractions coming from the outside world, internal triggers are those coming from within ourselves.&lt;/p&gt;
&lt;p&gt;In the book, Eyal explores how evolution has built into us the need for distraction.
"Our tendencies towards boredom, negativity bias, rumination, and hedonic adaptation conspire to make sure we're never satisfied for long."
It's this constant dissatisfaction that is responsible for our advancement as a species.
It is a powerful mechanism, but one that can backfire, preventing us from getting anything done.&lt;/p&gt;
&lt;p&gt;The best way to master distraction is simply to accept that it's a normal behavior of our brain, then learn to deal with it from within.&lt;/p&gt;
&lt;p&gt;I often procrastinate or get distracted when I have to do some tasks that I don't like, say pruning the Jira backlog.
Needless to say, neither procrastinating nor getting distracted helps to get rid of the annoying task sooner.
Eyal's practical suggestion to stay focused and tackle this annoying work is to reimagine the task.&lt;/p&gt;
&lt;p&gt;While pruning the Jira backlog might not be the most interesting work for me, there are ways to make it a bit more so.
For example, I can challenge myself to do so only using keyboard shortcuts.
Or, I could timebox it for 30 minutes and see how many tickets I can go through.&lt;/p&gt;
&lt;p&gt;If nothing seems to work to spark your interest, you can always use it as a training exercise in focus.
Fighting back distractions while working on that annoying task is like a training session for your focus muscles.&lt;/p&gt;
&lt;h3 id="prevent-distractions-with-pacts"&gt;Prevent Distractions with Pacts&lt;/h3&gt;
&lt;p&gt;As we've seen, being focused and Indistractable is as much a matter of keeping distractions out as it is of reigning ourselves in.
The final strategy Eyal proposes is to make pacts with our future selves to fight off distractions.
A pact is a precommitment we make against distraction and serves at keeping us in check.&lt;/p&gt;
&lt;p&gt;If you still find it hard to focus on your work after implementing the previous areas of the Indistractable model, you should consider putting some pacts in place to help you.&lt;/p&gt;
&lt;p&gt;You could, for example, implement an &lt;em&gt;effort pact&lt;/em&gt; and make unwanted behavior more difficult to do.
Make a deal with a coworker to work focused next to each other; the first one to get distracted pays lunch.
If the browser extension you set up to avoid going on social media is not enough to stop you, then ask a friend to change your password and give it back to you only when the weekend comes.
The added social pressure will make it harder to fall into unwanted behaviors.&lt;/p&gt;
&lt;p&gt;In my opinion, pacts are the least concrete of the strategies.
You should resolve to pacts only as a last resort.
The previous three steps are much better at creating habits and an environment conducive to long term quality focus.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The problem with productivity and self-help books is that they are like diet books.
A new one is published every week.
Most of them provide solid advice, although sometimes it's borderline common sense –of course, you shouldn't eat a tub of ice cream a day if you want to lose weight; of course, you shouldn't check your phone every 5 minutes if you're trying to write some complicated piece of code.
A productivity framework (or a diet) is only as effective as our ability to implement them.&lt;/p&gt;
&lt;p&gt;This post contains lots of advice, definitely too much to take on in one go, and Eyal's book even more so.
If you want to get started, I'd recommend you pick only one thing out of here and try it out over the next week.
Just one thing.
If you're successful, pick another one on top of it for the week after.
If you're not successful, don't beat yourself up.
Either try again or pick a different one.&lt;/p&gt;
&lt;p&gt;Doing something, no matter how little, is better than not doing anything at all.
If you agree with me that the quality of the work you produce is directly proportional to your value in the market, then any little improvement will pay off.
Even more so, if you manage to stack little improvement after little improvement.&lt;/p&gt;
&lt;p&gt;Grab yourself a copy of &lt;a href="https://geni.us/ayNk" rel="noopener noreferrer"&gt;Indistractable&lt;/a&gt; to learn more about the nuances of the framework.
And if you want to learn more about the value of focus and how to maintain it, &lt;a href="https://geni.us/FITEF" rel="noopener noreferrer"&gt;Deep Work&lt;/a&gt; is the go-to resource.&lt;/p&gt;
&lt;p&gt;I'd love to hear about the tactics you use to avoid distractions.
Happy focused work.&lt;/p&gt;


&lt;p&gt;&lt;em&gt;This is a crosspost from my blog, &lt;a href="http://www.mokacoding.com/blog/the-indistractable-developer/" rel="noopener noreferrer"&gt;mokacoding.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95330%2Fb45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/clutter-is-costly--optimization-matters-51ea" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Clutter is costly &amp;amp; Optimization matters&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Feb 28 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#books&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95330%2Fb45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/ten-productivity-books-you-won-t-regret-reading-38bh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Ten Productivity Books You Won't Regret Reading&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Mar 27 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#books&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95330%2Fb45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/is-social-media-in-charge-of-your-schedule-19h6" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Is social media in charge of your schedule?&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ May 2 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>productivity</category>
      <category>books</category>
    </item>
    <item>
      <title>Is social media in charge of your schedule?</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Thu, 02 May 2019 02:48:03 +0000</pubDate>
      <link>https://dev.to/mokagio/is-social-media-in-charge-of-your-schedule-19h6</link>
      <guid>https://dev.to/mokagio/is-social-media-in-charge-of-your-schedule-19h6</guid>
      <description>&lt;p&gt;A simple fact of life is that there are only 24 hours in a day.&lt;br&gt;
Whatever your definition of being productive is, a crucial part of achieving it is spending those 24 hours as best as you can.&lt;/p&gt;

&lt;p&gt;The average internet user spends more than 2 hours on social media a day.&lt;sup id="social-media-two-hours"&gt;1&lt;/sup&gt;&lt;br&gt;
I'd wager most of these people could spend that time better.&lt;/p&gt;

&lt;p&gt;But I'm not here to wage war against social media, preaching you should delete all your accounts today.&lt;br&gt;
On the contrary, if you think one or more platform is useful to you, you should keep using it.&lt;br&gt;
What I'd like to focus on is &lt;em&gt;how&lt;/em&gt; to use them.&lt;/p&gt;

&lt;p&gt;I'll use &lt;a href="https://twitter.com/mokagio" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; as a personal example.&lt;br&gt;
I have long stopped using Facebook and Instagram, but I look at Twitter almost daily.&lt;br&gt;
It's one of my sources of tech news, a way for me to share my work, and a place keep in touch with friends from the tech community.&lt;/p&gt;

&lt;p&gt;On the other hand, my browsing of Twitter can quickly degenerate into mindless scrolling looking for something to click, and before I know it I've wasted half an hour.&lt;/p&gt;

&lt;p&gt;To my defense, it's not &lt;em&gt;all&lt;/em&gt; my fault.&lt;br&gt;
It's not just a matter of will power.&lt;br&gt;
Twitter and all the other social media and infotainment platforms have spent years tailoring their webpages and apps to become engaging and addictive.&lt;br&gt;
These technologies exploit shortcomings of our brains to make us stay with them longer and return often, so we can see the ads that generate their revenue.&lt;br&gt;
&lt;a href="http://www.tristanharris.com/2016/05/how-technology-hijacks-peoples-minds%e2%80%8a-%e2%80%8afrom-a-magician-and-googles-design-ethicist/" rel="noopener noreferrer"&gt;This post&lt;/a&gt; by design ethicist &lt;a href="http://www.tristanharris.com/" rel="noopener noreferrer"&gt;Tristan Harris&lt;/a&gt; is an excellent introduction to the techniques they use.&lt;/p&gt;

&lt;p&gt;How can we use social media, infotainment sites, streaming platforms, and all the other inventions of the internet age productively?&lt;br&gt;
How can we get what we need out of them without being sucked in?&lt;/p&gt;

&lt;h2&gt;
  
  
  Social Media Operating Procedures
&lt;/h2&gt;

&lt;p&gt;In his book &lt;a href="https://geni.us/7HNOJAz" rel="noopener noreferrer"&gt;Digital Minimalism&lt;/a&gt; Cal Newport introduces the concept of &lt;em&gt;standard operating procedures&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In business lingo, a standard operating procedure is a "set of step-by-step instructions compiled by an organization to help workers carry out complex routine operations"&lt;sup id="sop"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Applied to social media and other entertainment platforms, these are rules that describe when and how to use those technologies.&lt;/p&gt;

&lt;p&gt;By clearly defining the way we interact with any given site or app we can counterbalance how tech giants have optimized their products to make us addicted.&lt;/p&gt;

&lt;p&gt;With these rules we can be more intentional in our usage of social media and the likes, taking control back into our own hands.&lt;/p&gt;

&lt;p&gt;Here's a concrete example. These are my operating procedures for Twitter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Twitter Operating Procedures
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only check Twitter twice a day; after lunch and after finishing work.&lt;/li&gt;
&lt;li&gt;No Twitter during the weekend, it's a time to spend with the family and rest.&lt;/li&gt;
&lt;li&gt;Stay away from the homepage and its engagement optimizations; use lists instead.&lt;/li&gt;
&lt;li&gt;Only check Twitter when alone, don't let it distract you from other people.&lt;/li&gt;
&lt;li&gt;No Twitter on the phone, to avoid the temptation of using it as a boredom fix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I mostly browse Twitter through the &lt;a href="https://tweetdeck.twitter.com/" rel="noopener noreferrer"&gt;TweetDeck&lt;/a&gt; desktop app.&lt;br&gt;
I like it because it allows you to show lists, notifications, etc. one next to the other, without ever having to visit the homepage.&lt;sup id="tweetdeck"&gt;*&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fmokacoding%2F2019-04-30-tweetdeck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fmokacoding%2F2019-04-30-tweetdeck.png" alt="A screenshot of my TweetDeck interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the web, I use the &lt;a href="https://github.com/sindresorhus/refined-twitter" rel="noopener noreferrer"&gt;refined Twitter plugin&lt;/a&gt; to remove a lot of the noise from the UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fmokacoding%2F2019-04-30-refined-twitter-github.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fmokacoding%2F2019-04-30-refined-twitter-github.gif" alt="Twitter with and without the refined Twitter plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to these simple rules and tweaks I have lost the urge, and I rarely end up scrolling mindlessly, without having to give up what I find valuable in the platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to develop your own operating procedures
&lt;/h2&gt;

&lt;p&gt;The goal of a standard operating procedure is to optimize your use of a given technology.&lt;/p&gt;

&lt;p&gt;You should develop your own procedures to get more value out of a platform and at the same time experience less of the negative aspects of it.&lt;/p&gt;

&lt;p&gt;Take a look at how you use the technology and think if there's a better way to get value out of it.&lt;br&gt;
You could use filters to only show content you really like, or bookmark the pages you want to keep up with to make them easier to reach while at the same time cutting off the distractions of the homepage.&lt;br&gt;
To stay up to date with the news, you could bypass shallow infotainment news aggregators and subscribe to a few highly curated newsletters instead.&lt;/p&gt;

&lt;p&gt;Also, think about what you don't like in a technology or in how you use it, is there a way to minimize that?&lt;br&gt;
In &lt;a href="https://geni.us/7HNOJAz" rel="noopener noreferrer"&gt;Digital Minimalism&lt;/a&gt; the author shares how one of his readers only watches Netflix with their partner, to avoid isolating themselves and binge watching.&lt;br&gt;
A friend of mine is into videogames but is also wary of how they tend to suck you in.&lt;br&gt;
He schedules a few hours of uninterrupted play a week, during which he's fully immersed in the game.&lt;br&gt;
This is enough to let him enjoy himself, and knowing he hasn't compromised his productivity gives him great satisfaction.&lt;br&gt;
Moreover, he has the next scheduled session to look forward to, which makes it even more enjoyable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time-bound
&lt;/h2&gt;

&lt;p&gt;A useful way to optimize your technology interactions is to trigger them at a particular time of the day or to time-box them.&lt;/p&gt;

&lt;p&gt;By scheduling the times in which you interact with social media you can add an extra layer of control and intentionality.&lt;br&gt;
A big danger of these technologies is that they need you to constantly use them during the day to make money.&lt;br&gt;
Having predetermined times to visit them is a way to resist the urge to have a quick look.&lt;/p&gt;

&lt;p&gt;For me, checking Twitter only at prefixed times was a shift from a reactive approach to a proactive one.&lt;br&gt;
Instead of "I feel slightly bored, let me mindlessly scroll," I now think "It's time to catch up with my feed."&lt;br&gt;
Not only you'll make it harder to become addicted, but you'll also enjoy the technology more, because you'll be intentionally using with it, rather than responding to a boredom stimulus.&lt;/p&gt;

&lt;p&gt;In the same way, time-boxing your interaction is a way to ensure these technologies don't take over your schedule.&lt;br&gt;
Admittedly, time-boxing requires will power.&lt;br&gt;
It's easy to say "just another few minutes," and quickly lose track of time.&lt;/p&gt;

&lt;p&gt;A way to make time-boxing easier is to automate it.&lt;br&gt;
Have a look at these tools to set time limits for interactions with apps and websites.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/stayfocusd/laankejkbhbdhmipfmgcngdelahlfoji" rel="noopener noreferrer"&gt;StayFocused&lt;/a&gt; is a browser plugin to limit the time spent on a blacklist of sites.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://freedom.to/" rel="noopener noreferrer"&gt;Freedom&lt;/a&gt; is a software to set time limits, and much more, across websites and other apps.&lt;/li&gt;
&lt;li&gt;With iOS 12, Apple introduced the ability to set &lt;a href="https://9to5mac.com/2018/10/16/time-limit-app-limit-iphone-ipad/" rel="noopener noreferrer"&gt;app-specific time limits&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The freedom of constraints
&lt;/h2&gt;

&lt;p&gt;A common concern with this scheduling approach is that it'll end up sucking away all the spontaneity from life.&lt;/p&gt;

&lt;p&gt;It turns out to be quite the opposite.&lt;br&gt;
Having allotted time slots for social media and other tasks frees up more time in my day for real spontaneous activities, like going for a walk, write to a friend, or have a tickle wrestle with my son.&lt;/p&gt;

&lt;p&gt;The more I structure my days around routines and rituals, the more I find myself relaxed, and in control.&lt;br&gt;
It's in the days in which my plans are disrupted that I end up being flustered and unproductive.&lt;/p&gt;

&lt;p&gt;If at any point during the day I feel like visiting Twitter, knowing I have already scheduled a time for it later settles my mind, avoiding what could have been a time consuming and focus ruining distraction.&lt;/p&gt;




&lt;p&gt;As software developers, it's easy to feel the urge to try out every new app and tool.&lt;br&gt;
It often feels like time well spent researching what other people are doing in the industry.&lt;br&gt;
The shiny new object syndrome applies as well to social media, apps, and infotainment websites as it does to frameworks and tools.&lt;/p&gt;

&lt;p&gt;The Digital Minimalism philosophy encourages us to take a thoughtful approach to the use we make of technologies in our lives.&lt;/p&gt;

&lt;p&gt;Critically assess every platform you use, and keep only the ones that are genuinely useful and in line with what you value.&lt;br&gt;
For those, ideally few, technologies that make the cut, take an extra step and make sure you optimize the way you use them so that they are value generating tools, not time sucking addictions.&lt;/p&gt;

&lt;p&gt;For me, Twitter is a technology with the potential to generate value.&lt;br&gt;
But for this potential to materialize, I need to be the one in charge of the interaction, not the other way around.&lt;br&gt;
Defining an operating procedure is a way to makes sure Twitter remains a tool for me, and I don't become a tool for Twitter.&lt;/p&gt;

&lt;p&gt;Being intentional and present in everything we do is a recipe for living a good life.&lt;br&gt;
Being intentional with how we interact with technology is a step in that direction.&lt;/p&gt;

&lt;p&gt;What technologies do you find valuables?&lt;br&gt;
Do you have operating procedures to interact with them?&lt;br&gt;
I'd love to hear from you, leave a comment below or get in touch on Twitter &lt;a href="https://twitter.com/mokagio" rel="noopener noreferrer"&gt;@mokagio&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Footnotes
&lt;/h3&gt;

&lt;p&gt;&lt;span id="fn1"&gt;&lt;/span&gt; "&lt;em&gt;more than 2 hours on social media a day.&lt;/em&gt;" Data from the &lt;a href="https://www.globalwebindex.com/" rel="noopener noreferrer"&gt;2019 GlobalWebIndex&lt;/a&gt; report, via &lt;a href="https://www.digitalinformationworld.com/2019/01/how-much-time-do-people-spend-social-media-infographic.html" rel="noopener noreferrer"&gt;Digital Information World&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;span id="fn2"&gt;&lt;/span&gt; "&lt;em&gt;set of step-by-step instructions compiled by an organization to help workers carry out complex routine operations&lt;/em&gt;." Source: &lt;a href="https://en.wikipedia.org/wiki/Standard_operating_procedure" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;span id="fn3"&gt;&lt;/span&gt; TweetDeck. The cynical in me wouldn't be surprised if Twitter soon removed the lists feature and sunset TweetDeck to force users to interact with their algorithmic timeline. Only time will tell.&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>How to run a single test in Xcode</title>
      <dc:creator>Gio Lodi</dc:creator>
      <pubDate>Wed, 24 Apr 2019 11:23:44 +0000</pubDate>
      <link>https://dev.to/mokagio/how-to-run-a-single-test-in-xcode-5h72</link>
      <guid>https://dev.to/mokagio/how-to-run-a-single-test-in-xcode-5h72</guid>
      <description>&lt;p&gt;When building software, you should try to &lt;strong&gt;optimize the speed of your feedback loop&lt;/strong&gt;.&lt;br&gt;
The faster you can learn if your code works and how, the better you'll be at delivering value to your users.&lt;/p&gt;

&lt;p&gt;When it comes to testing and TDD, a fast feedback loop means a test suite &lt;strong&gt;that runs in no more than a few seconds&lt;/strong&gt;.&lt;br&gt;
If I stare at a progress bar for more than a few seconds, my mind will start getting distracted.&lt;br&gt;
At that point, I'll have to expend a lot of mental energy not to set off to do something else and disrupt my concentration.&lt;/p&gt;

&lt;p&gt;Having a test suite that runs in a few seconds is hard though, especially as our codebases grow.&lt;br&gt;
A technique to speed up the feedback loop when working in a codebase with a long-running test suite is to &lt;strong&gt;only run a subset of the tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By running only the tests relevant to the code you're changing, you can significantly speed-up the suite execution time, increasing the speed of our feedback loop.&lt;/p&gt;

&lt;p&gt;Xcode offers a few different ways to run a subset of the tests.&lt;br&gt;
Let's take a look.&lt;/p&gt;
&lt;h2&gt;
  
  
  From the gutter
&lt;/h2&gt;

&lt;p&gt;You can run a single test class or a single test method by clicking the corresponding test diamond in the gutter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E_2uniNy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/mokacoding/2019-04-23-single-test-from-gutter.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E_2uniNy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/mokacoding/2019-04-23-single-test-from-gutter.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  With a keyboard shortcut
&lt;/h2&gt;

&lt;p&gt;Hit &lt;code&gt;^ ⌥ ⌘ U&lt;/code&gt; to run the tests for the cursor's &lt;em&gt;context&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you are inside a test method, like in the example below, the context will be that method.&lt;br&gt;
If your cursor is in a test class, but outside a method, the context will be that test calls; all its tests will run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dTi9B5kG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/mokacoding/2019-04-23-single-test-from-keyboard.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dTi9B5kG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/mokacoding/2019-04-23-single-test-from-keyboard.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I &lt;a href="https://xcodetips.com"&gt;love keyboard shortcuts&lt;/a&gt;, and this is &lt;a href="https://www.mokacoding.com/blog/xcode-testing-shortcuts/"&gt;my favorite testing shortcut&lt;/a&gt;. I use it many many times every day.&lt;/p&gt;
&lt;h2&gt;
  
  
  From the scheme
&lt;/h2&gt;

&lt;p&gt;Another way to run a subset of tests is to select them in the scheme configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YXB_eTaO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/mokacoding/2019-04-23-scheme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YXB_eTaO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/mokacoding/2019-04-23-scheme.png" alt="Image showing a scheme configuration with a subset of tests selected"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can only think of a handful of cases when you might want to use this approach.&lt;br&gt;
For example, you might have a long-running integration suite that would slow down your continuous integration pipeline.&lt;br&gt;
You could create a new scheme with only the core tests in the suite and run only those on CI for every repository check-in while keeping the long-running suite as something you run every night.&lt;/p&gt;

&lt;p&gt;I'm wary of this approach.&lt;br&gt;
These configurations are buried in the scheme settings; it's far too easy to forget about them.&lt;br&gt;
You might disable some tests and accidentally check-in the change to the scheme, and suddenly find yourself missing an important part of your unit tests suite.&lt;/p&gt;
&lt;h2&gt;
  
  
  From the terminal
&lt;/h2&gt;

&lt;p&gt;If you are running your tests from the terminal, you can use the &lt;code&gt;-only-testing&lt;/code&gt; &lt;code&gt;xcodebuild&lt;/code&gt; flag to run a subset of tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcodebuild test \
  -scheme YourScheme \
  -project YourProject.xcodeproj \
  -destination 'platform=iOS Simulator,name=iPhone Xs' \
  -only-testing YourTests/YourClassTests/testSomething
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can add as many &lt;code&gt;-only-testing&lt;/code&gt; as you want.&lt;/p&gt;

&lt;p&gt;The option supports different granularities of identifiers: &lt;code&gt;TestTarget[/TestClass[/TestMethod]]&lt;/code&gt;.&lt;br&gt;
This means that in the example above you can run all the tests in &lt;code&gt;YourClassTests&lt;/code&gt; by using &lt;code&gt;-only-testing YourTests/YourClassTests&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Worth noting that you can also run all the tests other than a subset, using the &lt;code&gt;-skip-testing&lt;/code&gt; option instead.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bonus: Focused tests in Quick
&lt;/h2&gt;

&lt;p&gt;If you are using the testing framework &lt;a href="https://github.com/Quick/Quick"&gt;Quick&lt;/a&gt; to enjoy a more descriptive way of defining your tests you might notice that Xcode doesn't add the diamonds in the gutter.&lt;/p&gt;

&lt;p&gt;You can still run a subset of tests by &lt;a href="https://github.com/Quick/Quick/blob/0b4ed6c706dd0cce923b5019a605a9bcc6b1b600/Documentation/en-us/QuickExamplesAndGroups.md#temporarily-running-a-subset-of-focused-examples"&gt;&lt;em&gt;focusing&lt;/em&gt;&lt;/a&gt; them.&lt;br&gt;
This can be done by adding an &lt;code&gt;f&lt;/code&gt; in front of on an example or group: &lt;code&gt;fit&lt;/code&gt;, &lt;code&gt;fcontext&lt;/code&gt;, &lt;code&gt;fdescribe&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"is loud"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...only this focused example will be run.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"has a high frequency"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...this example is not focused, and will not be run.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  A word of caution
&lt;/h2&gt;

&lt;p&gt;Running one test or a subset of tests will make your feedback loop faster, but will also reduce the confidence in your change not breaking any part of the codebase.&lt;/p&gt;

&lt;p&gt;My recommendation is to run the subset of tests for the code you are working on only during the intermediate steps of development.&lt;br&gt;
Once you're done implementing the change, fix, or feature, run the whole test suite.&lt;br&gt;
Develop the habit of always running the tests before committing, and never make a commit if the tests are not passing.&lt;/p&gt;



&lt;p&gt;What do you think of these methods to run a single test in Xcode? Do you know any other?&lt;/p&gt;

&lt;p&gt;I'd love to hear from you, get in touch on Twitter &lt;a href="https://twitter.com/mokagio"&gt;@mokagio&lt;/a&gt; or leave a comment below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a crosspost from my blog &lt;a href="https://www.mokacoding.com/blog/running-one-test-in-xcode/"&gt;mokacoding.com&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6vNuVRNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--20YcS3et--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/95330/b45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/how-to-tdd-in-swift-a-step-by-step-guide-8jg" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to TDD in Swift, a step by step guide&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Feb 13 '19 ・ 14 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#tdd&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#swift&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6vNuVRNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--20YcS3et--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/95330/b45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/how-to-test-view-controllers-navigation-3hhh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to test view controllers navigation&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Apr 17 '19 ・ 5 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#swift&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ios&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;a href="/mokagio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6vNuVRNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--20YcS3et--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/95330/b45c8aef-ca62-4077-ac9b-6b0967f38ebf.jpeg" alt="mokagio image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mokagio/code-coverage-is-a-broken-metric-3aac" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Code Coverage Is A Broken Metric&lt;/h2&gt;
      &lt;h3&gt;Gio Lodi ・ Feb 20 '19 ・ 4 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#refactoring&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>xcode</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
