<?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>Forem: Kate</title>
    <description>The latest articles on Forem by Kate (@kalabro).</description>
    <link>https://forem.com/kalabro</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%2F68522%2Fb6d65e78-940e-40c6-a2b8-d2408bf9a94d.jpg</url>
      <title>Forem: Kate</title>
      <link>https://forem.com/kalabro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kalabro"/>
    <language>en</language>
    <item>
      <title>It depends! Exploring my favourite Renovate features for dependency updates</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Sun, 18 Jun 2023 13:06:56 +0000</pubDate>
      <link>https://forem.com/kalabro/it-depends-exploring-my-favourite-renovate-features-for-dependency-updates-3j5a</link>
      <guid>https://forem.com/kalabro/it-depends-exploring-my-favourite-renovate-features-for-dependency-updates-3j5a</guid>
      <description>&lt;p&gt;I learned about &lt;a href="https://docs.renovatebot.com/"&gt;Renovate&lt;/a&gt; a couple of years ago when I was trying to group automated updates in Dependabot. It's 2023, and Dependabot is &lt;a href="https://github.com/dependabot/dependabot-core/issues/1190"&gt;still figuring out&lt;/a&gt; how to implement grouping. Not blaming them; dependency updates are challenging. Regardless of the approach you take, a fair amount of work is required to set up tools and processes for dependency management. In this post, I have collected a few of my favourite features and tricks when working with Renovate. Have I missed anything? Of course! Renovate is highly configurable (and well-documented), so if you need the full guide, please consult the official docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Renovate works
&lt;/h2&gt;

&lt;p&gt;Before delving into the details, let's ask ChatGPT for a quick summary of how Renovate works:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Renovate is an open-source tool designed to automate the process of updating dependencies in a project. It works by identifying relevant package files within a codebase (including monorepos), then generating and scheduling pull requests to update those dependencies and their associated lock files. Users have the ability to customise the behaviour of the Renovate bot through configuration files and share configurations using ESLint-like presets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The easiest way to get started with Renovate is to install it in your repo as a &lt;a href="https://github.com/apps/renovate"&gt;GitHub App&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vSDuCz-b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/b523c952ef5f4caa2b6a3cf4abb07df7/de4d5/install-on-github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vSDuCz-b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/b523c952ef5f4caa2b6a3cf4abb07df7/de4d5/install-on-github.png" alt="Install Renovate via GitHub App" width="800" height="1015"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Renovate will automatically open a &lt;a href="https://github.com/kalabro/kalabro.tech/pull/42"&gt;"Configure Renovate" PR&lt;/a&gt; with meaningful defaults. Once the config file is merged, Renovate will start opening regular pull requests with dependency updates. In theory, that's it. In practice, you'll likely want to tweak the configuration and fine-tune it to suit your specific needs and preferences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 1: config presets
&lt;/h2&gt;

&lt;p&gt;Renovate supports hundreds of configuration options, or at least it feels that way. The resulting configuration file, even for a simple app, can end up being huge and cryptic. Fortunately, Renovate provides config presets that allow you to abstract away the details and share config pieces across multiple projects.&lt;/p&gt;

&lt;p&gt;One crucial config preset to be aware of is &lt;a href="https://docs.renovatebot.com/presets-config/#configbase"&gt;config:base&lt;/a&gt;. It enables core Renovate features such as the Dependency Dashboard and monorepo grouping (more on this later in the article). It's a good idea to base your configuration on &lt;code&gt;config:base&lt;/code&gt; or, in the case of JavaScript projects, on the &lt;code&gt;config:js-app&lt;/code&gt; or &lt;code&gt;config:js-lib&lt;/code&gt; presets.&lt;/p&gt;

&lt;p&gt;Here is an example configuration for my personal blog powered by Gatsby:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;$schema:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://docs.renovatebot.com/renovate-schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;up&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;supported&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;properties&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;extends:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"config:js-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;recommended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;applications&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"schedule:monthly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;schedule:weekly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;schedule:weekends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;etc&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"npm:unpublishSafe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;must&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;least&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;days&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;old&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;":approveMajorUpdates"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;explicit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;approval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dashboard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;opening&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PR&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;":maintainLockFilesWeekly"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;regenerates&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;indirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;deps&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;transitiveRemediation:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;security&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;updates&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;indirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(transitive)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;NPM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dependencies&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it's a JavaScript project, I used the &lt;code&gt;config:js-app&lt;/code&gt; preset. I configured the update schedule, enabled the minimum release days restriction, disabled automatic PRs for major updates, and enabled weekly lock file maintenance. All using the default config presets. Thanks to JSON5 support, I can add comments to my config!&lt;/p&gt;

&lt;p&gt;If I have multiple projects similar to this one, I can convert my new configuration into a preset and refer to it in the config of the other projects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;$schema:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://docs.renovatebot.com/renovate-schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;extends:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"github&amp;gt;kalabro/kalabro.tech//renovate/js-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;loads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;my&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;another&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;repo&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Further&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;extending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;specific&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;project&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;postUpdateOptions:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"yarnDedupeHighest"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It assumes that my shareable config is available at &lt;code&gt;https://github.com/kalabro/kalabro.tech/renovate/js-app.json&lt;/code&gt;. As you probably guessed, you can keep customising the final config using other presets or configuration options. For example, you may need to group (or exclude) certain dependencies to reduce update noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 2: grouping related updates
&lt;/h2&gt;

&lt;p&gt;My blog has 20 Gatsby-related dependencies (what a mess, but it's a topic for another blog post 😄). Updating them one by one is distracting and also likely to cause issues. What if we could ask Renovate to group all gatsby-* dependencies in one PR? No problem at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"packageRules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matchPackagePatterns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"^gatsby"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"groupName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gatsby packages"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.renovatebot.com/configuration-options/#packagerules"&gt;packageRules&lt;/a&gt; is a cool and flexible config option for grouping Renovate updates. However, in my case, it's not even necessary! My default config already has built-in knowledge on how to group &lt;a href="https://docs.renovatebot.com/presets-monorepo/#monorepogatsby"&gt;Gatsby dependencies&lt;/a&gt;, thanks to Renovate's base preset. It encompasses a wide range of curated package rules, especially for the Javascript ecosystem. Whether it's Angular, Vue, or anything in between, Renovate has you covered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--szc8r2SY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/236053838f121303d7fde730511b423a/2fad1/gatsby-monorepo-pr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--szc8r2SY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/236053838f121303d7fde730511b423a/2fad1/gatsby-monorepo-pr.png" alt="Renovate groups all Gatsby updates in one PR" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few typical use cases for the packageRules configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separating dependencies and devDependencies. The latter is easier to automerge.&lt;/li&gt;
&lt;li&gt;Modifying the update schedule for specific types or groups of updates.&lt;/li&gt;
&lt;li&gt;Restricting updates for certain packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A word of caution. Although it may seem counterintuitive, I have found that smaller and more frequent updates tend to be more effective than large grouped PRs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 3: lock file updates
&lt;/h2&gt;

&lt;p&gt;Renovate performs update checks for your direct dependencies, which are the ones listed in the package.json file. These direct dependencies can themselves have their own dependencies, which are known as indirect or transitive dependencies. Typical web projects often have much more transitive dependencies than direct ones. The easiest way to keep these dependencies up to date is by regularly refreshing the lock file. When you combine this approach with &lt;a href="https://docs.renovatebot.com/dependency-pinning/"&gt;dependency pinning&lt;/a&gt;, lock file updates can be safely automated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  $schema: "https://docs.renovatebot.com/renovate-schema.json",
  extends: [
    "config:js-app",  // pins dependencies in package.json file
    ":maintainLockFilesWeekly", // regenerates lock file to update all transitive deps 
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you prefer ranges (&lt;code&gt;"^1.2.3"&lt;/code&gt;) to pinning (&lt;code&gt;"1.2.3"&lt;/code&gt;), lock file maintenance &lt;strong&gt;will update everything&lt;/strong&gt; according to the ranges specified in your package.json. If this is what you are looking for, take a look at &lt;a href="https://docs.renovatebot.com/presets-config/#configsemverallmonthly"&gt;&lt;code&gt;config:semverAllMonthly&lt;/code&gt;&lt;/a&gt; preset for inspiration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 4: Dependabot integration
&lt;/h2&gt;

&lt;p&gt;Wait, what?&lt;br&gt;&lt;br&gt;
Yes, Renovate delegates vulnerability checks to Dependabot. When running on GitHub, Renovate checks Dependabot security alerts and immediately triggers the corresponding updates. To utilise this feature, you need to enable Dependabot alerts in your project settings.&lt;/p&gt;

&lt;p&gt;A vulnerability remediation PR may appear as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dBgjHx3l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/7fcd28733b07e3f47e28aec1278caee2/6c362/security-pr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dBgjHx3l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/7fcd28733b07e3f47e28aec1278caee2/6c362/security-pr.png" alt="Vulnerability remediation PR" width="800" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, this feature is configurable via the &lt;a href="https://docs.renovatebot.com/configuration-options/#vulnerabilityalerts"&gt;vulnerabilityAlerts&lt;/a&gt; setting.&lt;br&gt;&lt;br&gt;
You can also override the &lt;a href="https://docs.renovatebot.com/configuration-options/#prbodytemplate"&gt;&lt;code&gt;prBodyTemplate&lt;/code&gt;&lt;/a&gt; setting to remove the Renovate banner at the top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 5: Dependency Dashboard
&lt;/h2&gt;

&lt;p&gt;For quite a while, I thought Renovate was a typical CI tool without UI. Luckily, I was mistaken. Renovate comes with a Dependency Dashboard where you can find a summary of all opened and pending updates, as well as any configuration issues. Below is a screenshot of the &lt;a href="https://github.com/kalabro/kalabro.tech/issues/43"&gt;Dependency Dashboard&lt;/a&gt; for this blog (don't worry about all the security issues, it's a static website):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FTceyUZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/f892bc18534b692eee47db579491ba05/d0ad5/dashboard-issue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FTceyUZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/f892bc18534b692eee47db579491ba05/d0ad5/dashboard-issue.png" alt="Dependency Dashboard" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of jumping back and forth between different PRs and Renovate app logs, I can view and manage everything from one place. It's even more helpful when you're maintaining multiple repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise
&lt;/h2&gt;

&lt;p&gt;If you're seeking an automated dependency management tool, I can confidently recommend Renovate. It's well-designed, flexible, and open source. After using it for over a year, I particularly enjoy some of its features, such as shareable configs and the Dependency Dashboard. However, be aware that the initial learning curve can be steep, especially if can't use the preconfigured GitHub app.&lt;/p&gt;

&lt;p&gt;Are you using Renovate or any other dependency management tool? I'd love to know about your experience in the comments!&lt;/p&gt;

</description>
      <category>security</category>
      <category>dependencies</category>
      <category>devops</category>
    </item>
    <item>
      <title>Budgeting my communication capacity</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Sat, 03 Jun 2023 18:43:25 +0000</pubDate>
      <link>https://forem.com/kalabro/budgeting-my-communication-capacity-pb5</link>
      <guid>https://forem.com/kalabro/budgeting-my-communication-capacity-pb5</guid>
      <description>&lt;p&gt;&lt;em&gt;Spring 2023 was fun. After 7 years in one company, I started a new role in a very different type of business, with a very different tech stack. Bold move for me! The entire process from interviewing to signing an offer to opening my first PR in a new team took almost a year. Landing a job in tech is hard. "The system is broken" is a common phrase to hear when engineers of all seniority levels share their hiring experiences. Funny enough, my new job is to build products for recruiters. Let's see if I can help to "fix the system." I'll start by sharing some learnings from my recent job change project. And the first one is all about networking.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZdAmWxa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4cn2ms73oq8b62qwkxq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZdAmWxa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4cn2ms73oq8b62qwkxq.jpg" alt='Kate is reading a book "Cracking coding interview" to her pets, cat and dog' width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm an introvert. I enjoy the comfort and solitude of remote work with async communication. When I'm in the flow, I can solve a wide range of technical problems from backend to frontend, from planning to shipping, from enterprise to greenfield. &lt;/p&gt;

&lt;p&gt;Out of 100%, 80% of my capacity is technical, and the remaining 20% is communication skills. However, those 20% were barely enough to support all of my technical work, especially when I started taking on more management responsibilities. I had ambition, and growing often meant management.&lt;/p&gt;

&lt;p&gt;Introverts on the other side of the screen will understand that once you've spent all your communication budget, it's a hard stop. I had been working like this for years, not leaving any of my "extrovert" budget for the outer IT space.&lt;/p&gt;

&lt;p&gt;As a result, when it was time to move on, I had very few useful connections and an outdated understanding of the IT recruitment market. I had to go through cold interviews with their live coding sessions, algorithmic problems, personality tests, and other humiliating experiences. Not fun at all.&lt;/p&gt;

&lt;p&gt;The most popular advice I received during that period was to keep interviewing. I was told to schedule as many interviews as possible until I became comfortable with them. I was advised to stretch my 20% even further.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Today, I have a better advice for myself: budget your communication capacity to stay in sync with the IT reality.&lt;/strong&gt;&lt;br&gt;
This means reserving 5% of my extravert capacity for external activities and spending that 5% wisely. Booking every morning for yet another interview call is not wise at all.&lt;/p&gt;

&lt;p&gt;While 5% may seem like a small number, there are many activities in IT that bring a lot of value with just a bit of communication effort. Let me share some concrete examples that have worked for me:&lt;/p&gt;

&lt;h2&gt;
  
  
  Meetups and conferences
&lt;/h2&gt;

&lt;p&gt;I found my current employer on meetup.com. I have also built strong connections with people I met at meetups and conferences. For me, the best way to network at a conference is to give a talk. This way, people come to me with specific questions, and I don't need to worry about how to start a conversation. I can also build good relationships with other speakers by giving feedback and asking follow-up questions. Even if I don't create any meaningful connections, I go home inspired and motivated. Good enough for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mentorship and coaching
&lt;/h2&gt;

&lt;p&gt;I feel much more comfortable in deeper 1:1 conversations than in group activities with strangers. Mentorship sessions were the main source of energy for me in 2022. I spoke to engineers and leaders from various organisations, and  everyone was very helpful and supportive. Today, I have a couple of trusted mentors, and offer engineering mentorships myself on &lt;a href="https://adplist.org/mentors/kate-marshalkina"&gt;ADPList&lt;/a&gt;. If you are new to mentorship read my post &lt;a href="https://kalabro.tech/where-to-find-mentor-2023/"&gt;"Where to find a mentor"&lt;/a&gt; to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blogging
&lt;/h2&gt;

&lt;p&gt;I created this little blog five years ago when I was playing with Gatsby during Christmas. Even with my occasional writing, it has become a great foundation for my public profile. As a bonus, it makes a positive first impression on recruiters. Writing skills are important in tech, as a lot of communication and knowledge sharing happens asynchronously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading
&lt;/h2&gt;

&lt;p&gt;Surprisingly, reading can be a decent networking tool. Writing a book review, giving a recommendation or participating in a book club - all of these activities can bring interesting people and ideas into my life. My &lt;a href="https://kalabro.tech/learning-domain-driven-design-book/"&gt;"Learning Domain-Driven Design" book review&lt;/a&gt; is the most popular post on this blog to date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working from the office
&lt;/h2&gt;

&lt;p&gt;To reserve some communication capacity for the activities mentioned above, I left behind my Tech Lead role and started as an individual contributor. However, as a Senior Engineer, I still have a lot of meetings to plan the work, pair on implementation, and stay up to date with the business in general. I was surprised to find out that all those activities drain me much less when I work from the office. Also, drawing on the whiteboard is a lot of fun!&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that didn't work for me
&lt;/h2&gt;

&lt;p&gt;I'm not the first to discover the difficulties with networking for less outgoing engineers, and I know there are many other ways to show up in the global IT community. Some of them didn't work for me (but they may work for you):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dale Carnegie tricks&lt;/strong&gt;&lt;br&gt;
Not my thing, but I agree that learning some "tricks" can help in common situations, like starting a conversation with a stranger or having an argument with a colleague.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Online communities&lt;/strong&gt;&lt;br&gt;
There are many topic-specific channels in Slack, Reddit, Discord, Twitch, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open Source contributions&lt;/strong&gt;&lt;br&gt;
Early in my career, I was lucky to meet great people from the Drupal open-source community. They influenced my career more than anyone else. Participating in open source requires time and effort, and at some point I disengaged in favor of client work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Freelance gigs&lt;/strong&gt;&lt;br&gt;
I know some very well-connected freelancers, but I'm not sure if my 5% communication budget will be enough to satisfy any client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building side projects&lt;/strong&gt;&lt;br&gt;
Building something public can be a great starting point for building connections with very interesting, well-connected people. Pretty much every indie developer I met was a very interesting person with multiple talents.&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise
&lt;/h2&gt;

&lt;p&gt;As an introvert, I have a limited communication capacity that I refer to as my "extravert budget". In the past, I used to spend all of it at work, leaving nothing for other activities. My recent job change experience has made it clear to me that I need to budget my communication capacity wisely. Otherwise, I'm at risk of alienating from the global IT community.&lt;/p&gt;

&lt;p&gt;Firstly, I gave up some of my management responsibilities and made it a habit to come to the office twice a week. Surprisingly, in-person meetings drain me much less compared to Zoom calls. Additionally, I began working with a mentor to enhance the efficiency of my communication.&lt;/p&gt;

&lt;p&gt;By making these changes, I am now able to engage more with the global IT community and naturally expand my professional network. I have found several activities that work well for me, such as meetups, mentorship, and blogging. &lt;/p&gt;

&lt;p&gt;I'd love to know what works for you, especially if you consider yourself a less outgoing person. Please, share your experience in comments below or contact me directly. Let's connect! 😄&lt;/p&gt;

</description>
      <category>career</category>
      <category>softskills</category>
      <category>growth</category>
    </item>
    <item>
      <title>Fast by default with Next.js</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Tue, 21 Feb 2023 08:58:06 +0000</pubDate>
      <link>https://forem.com/kalabro/fast-by-default-with-nextjs-594m</link>
      <guid>https://forem.com/kalabro/fast-by-default-with-nextjs-594m</guid>
      <description>&lt;p&gt;There is a famous quote from Donald Knuth that premature performance optimisation is the root of all evil. As usually happens with quotes, it was often taken out of context and amplified.&lt;/p&gt;

&lt;p&gt;It’s 2023, and despite all the efforts, the web remains slow. Developers tend to blame frameworks, programming languages, browsers, and even customers who constantly change requirements. Every new library or tool states that it’s blazing fast, yet we keep building slow sites with it.&lt;/p&gt;

&lt;p&gt;If we compare React bundle size throughout the years, it hasn’t significantly grown. What has grown is the amount of our own code written on top of React. It has grown so much that React itself started shifting its parts to the server (Server Components), which sounds insane for a frontend library!&lt;/p&gt;

&lt;p&gt;In this article, we will see how the Next.js framework encourages performance-first development by offering or even enforcing several web optimisations out of the box. None of them are specific to Next.js. We can (and should) implement them using any other web development tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript Code Splitting&lt;/li&gt;
&lt;li&gt;Preload JavaScript on link visibility&lt;/li&gt;
&lt;li&gt;Dynamic import&lt;/li&gt;
&lt;li&gt;Third-party scripts&lt;/li&gt;
&lt;li&gt;Fonts&lt;/li&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Static optimisation&lt;/li&gt;
&lt;li&gt;Edge Middleware&lt;/li&gt;
&lt;li&gt;React Server Components and streaming SSR&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  JavaScript Code Splitting&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;From the very beginning, Next.js provided a page-based routing system. To make your app available at example.com/about you had to create &lt;code&gt;pages/about.js&lt;/code&gt; file in Next.js. Many developers found this structure intuitive and easy to use.&lt;/p&gt;

&lt;p&gt;Under the hood, it allowed Next.js to implement &lt;a href="https://www.patterns.dev/posts/route-based/"&gt;Route-based Splitting&lt;/a&gt;, which was further optimised in &lt;a href="https://nextjs.org/blog/next-9-2#improved-code-splitting-strategy"&gt;version 9.2&lt;/a&gt; to benefit from HTTP/2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preload JavaScript on link visibility&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Once we break our JS into multiple chunks, we must ensure they are loaded at the right time. Link component form Next.js prefetches corresponding page code using &lt;a href="https://www.patterns.dev/posts/import-on-visibility/"&gt;Import on Visibility&lt;/a&gt; or &lt;a href="https://www.patterns.dev/posts/import-on-interaction/"&gt;Import On Interaction&lt;/a&gt; patterns.&lt;/p&gt;

&lt;p&gt;As you scroll down the notion.so website, you can notice some extra scripts are being loaded. If you then decide to go to another page, all necessary JavaScript will be already in place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---QgSz4oK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/8acfbc8f6d7801ca47d41a159dd6baee/16cb4/prefetched-pages.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---QgSz4oK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/8acfbc8f6d7801ca47d41a159dd6baee/16cb4/prefetched-pages.png" alt="By the time I scrolled to the footer, 29 page bundles have been loaded" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic import&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Heavy code that is only used under certain circumstances can be lazy-loaded using Dynamic Import. This technique requires developers first to identify candidates for lazy loading and then implement a smooth loading experience for the user.&lt;/p&gt;

&lt;p&gt;For many years, Next.js has been offering &lt;a href="https://nextjs.org/docs/advanced-features/dynamic-import"&gt;&lt;code&gt;next/dynamic&lt;/code&gt;&lt;/a&gt; function for this purpose. Under the hood, it’s just a wrapper around &lt;code&gt;React.lazy&lt;/code&gt; and &lt;code&gt;Suspense&lt;/code&gt; that you can use in any React project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Third-party scripts&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As you may know, &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag behaviour is very complex. An external script can completely ruin your Web Vitals regardless of how well you optimise your code. Below is a quote from a brilliant tutorial by the Google team &lt;a href="https://www.patterns.dev/posts/loading-sequence/"&gt;“Optimise your loading sequence”&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Scripts get different priorities based on where they are in the document and whether they are async, defer, or blocking. Blocking scripts requested before the first image ( or an image early in the document) are given higher priority over blocking scripts requested after the first image is fetched. Async/defer/injected scripts, regardless of where they are in the document, have the lowest priority. Thus we can prioritise different scripts by using the appropriate attributes for async and defer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main takeaway is that there is no one right way to include scripts on the site. We need to consider the entire loading sequence, versions of frameworks and browsers, the target audience of the site and a handful of other factors.&lt;/p&gt;

&lt;p&gt;Back to Next.js, its &lt;a href="https://nextjs.org/docs/basic-features/script"&gt;&lt;code&gt;&amp;lt;Script&amp;gt;&lt;/code&gt;&lt;/a&gt; component provides a simplified interface for HTML &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/script.js"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code can be put anywhere in the app, and Next.js will load it at the most appropriate time (after the page becomes interactive). It’s best for most scripts, such as Google Tag Manager or Google Analytics.&lt;/p&gt;

&lt;p&gt;If you need to load the script much earlier (or much later), you can use the &lt;code&gt;strategy&lt;/code&gt; property.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fonts&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The easiest way to optimise Largest Contentful Paint (LCP) metric is to place a large text block at the top of your page. For example, Next.js homepage uses &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; as LCP element:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XTLnwQl5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/4b7067802f951da1443308c359ab5fa3/56171/nextjs-lcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XTLnwQl5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/4b7067802f951da1443308c359ab5fa3/56171/nextjs-lcp.png" alt="nextjs.org LCP in PageSpeed Insights report" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Commonly, web designs are based on non-standard fonts aka &lt;em&gt;web fonts&lt;/em&gt;. Loading them from Google Fonts or similar services takes precious time and creates other issues like Cumulative Layout Shift (CLS).&lt;/p&gt;

&lt;p&gt;Next.js team has been working on fonts optimisation since version 10. They started with inlining font CSS and adding &lt;code&gt;&amp;lt;link preconnect&amp;gt;&lt;/code&gt; hint for the browsers and by &lt;a href="https://nextjs.org/blog/next-13#nextfont"&gt;version 13&lt;/a&gt; ended up with built-in self-hosting and optimisation for any font file.&lt;/p&gt;

&lt;p&gt;Font optimisation is hard, and I’m incredibly grateful to the Next.js team for handling it for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Images&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;On many websites, the main contributor to performance issues is media. When I work on performance, I always start with images. They are usually easy to fix and bring an immediate, noticeable boost.&lt;/p&gt;

&lt;p&gt;Thanks to WebP and AVIF, lazy loading and aspect-ratio, srcset and picture tag, we can deliver the most appropriate images to our users. Next.js offers a smart wrapper around &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag that utilises all mentioned techniques (and probably more) to reduce the amount of development work required to render an image in 2023.&lt;/p&gt;

&lt;p&gt;Below is a screenshot with the resulting markup generated by Next.js Image component from &lt;a href="https://github.com/vercel/next.js/tree/canary/examples/image-component"&gt;this example&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SjT8bfFV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/cff18956423ed6b389546cccd02abf97/16cb4/nextjs-image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SjT8bfFV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/cff18956423ed6b389546cccd02abf97/16cb4/nextjs-image.png" alt="The resulting markup generated by Next.js Image component" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As with any opinionated solution, &lt;code&gt;next/image&lt;/code&gt; has its limitations, but it’s a great starting point that sets the bar high.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static optimisation&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A few years ago, the industry became obsessed with Static Site Generation (SSG). Good old static HTML was back under a fancy name. This very site was built using an early GatsbyJS version.&lt;/p&gt;

&lt;p&gt;Indeed, static sites are more secure, faster, and cheaper. In 2020, &lt;a href="https://nextjs.org/blog/next-9-3#next-gen-static-site-generation-ssg-support"&gt;Next.js announced&lt;/a&gt; Automatic Static Optimisation: a simple API that uses SSG for static parts of the app while serving the rest of the app dynamically.&lt;/p&gt;

&lt;p&gt;Most dynamic sites couldn’t benefit from SSG at that time. First of all, it would require a massive rewrite. But the main problem was to trigger rebuilds every time you needed to update your static pages. We at SystemSeed overcame this issue by using Cloudflare CDN cache. You can learn more about this approach in my article &lt;a href="https://kalabro.tech/serve-like-static/"&gt;“Let Cloudflare CDN speed up your classic website like it’s static”&lt;/a&gt;. Guillermo Rauch, Vercel’s CEO, later contacted me about that article:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9i2hOd02--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/bcc1f7f0a52aa707812871e1cb414efb/c03d3/guillermo-rauch-cloudflare-cache.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9i2hOd02--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/bcc1f7f0a52aa707812871e1cb414efb/c03d3/guillermo-rauch-cloudflare-cache.png" alt="Guillermo Rauch, Vercel’s CEO, later contacted me about my article “Let Cloudflare CDN speed up your classic website like it’s static”" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Messages like this are the greatest reward for the author! 💚&lt;/p&gt;

&lt;p&gt;These days Next.js provides a built-in way to regenerate static pages. It’s called &lt;a href="https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration"&gt;Incremental Static Regeneration (ISR)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge Middleware&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Next.js is funded by Vercel, a hosting platform that’s primary focus is speed. While most Next.js performance features are hosting-neutral, some are harder to self-host. &lt;a href="https://vercel.com/docs/concepts/functions/edge-middleware"&gt;Edge Middleware&lt;/a&gt; is a good example. It’s inspired by (and based on) Cloudflare Workers. If you are a Vercel customer, you can immediately benefit from blazing-fast edge computing without leaving your favourite framework codebase. Amazing!&lt;/p&gt;

&lt;p&gt;But even if we are not on Vercel, their setup inspires us to build something similar with the tools available to us.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vercel deploys the middleware code to edge functions, which are invoked before the request reaches the CDN. This allows static pages can be cached, as the middleware is called before the CDN sends back a cached response&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The quote above is from the &lt;a href="https://github.com/serverless-stack/open-next"&gt;OpenNext&lt;/a&gt; project, which aims to port Vercel setup to other serverless platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Server Components and streaming SSR&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;From React 18 release notes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In React 18, you can start using Suspense for data fetching in opinionated frameworks like Relay, Next.js, Hydrogen, or Remix. Ad hoc data fetching with Suspense is technically possible, but still not recommended as a general strategy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;React is getting more complicated. It took several years to release Suspense, and it will take another few years to adopt it. Given the level of complexity, it’s wise to delegate implementation details to experienced frameworks’ maintainers.&lt;/p&gt;

&lt;p&gt;Next.js 13, the latest release to date, introduces a new routing system that supports streaming SSR, Server Components, and Suspense for data fetching. By pushing more code to the server, we can reduce the client-side JavaScript and speed up hydration.&lt;/p&gt;

&lt;p&gt;If you are new to React Server Components, I recommend to start with &lt;a href="https://beta.nextjs.org/docs/rendering/fundamentals"&gt;Rendering Fundamentals&lt;/a&gt; documentation. Welcome to the new Next.js!&lt;/p&gt;

&lt;p&gt;I’m sure the old pages routing will keep working for a while, but the new things will all go to the &lt;code&gt;app&lt;/code&gt; directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise
&lt;/h2&gt;

&lt;p&gt;I welcome you to rethink Knuth’s words about premature performance optimisation and embrace the “Fast by default” mindset when building websites. Not all optimisations are evil. Some of them have become common sense and should be applied &lt;em&gt;by default&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Next.js is an excellent example of the “fast by default” mindset. It popularises web performance best practices by making them easy to use (or even enforcing on ESLint level). I like this approach and apply it to other tools.&lt;/p&gt;

&lt;p&gt;Similar to mobile-first or security-first development cultures, it takes time to establish “fast by default” mindset, and I’m grateful to Next.js for helping me with it.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>performance</category>
    </item>
    <item>
      <title>🔭 Three tricks to get in focus mode</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Sun, 05 Feb 2023 16:43:56 +0000</pubDate>
      <link>https://forem.com/kalabro/three-tricks-to-get-in-focus-mode-332</link>
      <guid>https://forem.com/kalabro/three-tricks-to-get-in-focus-mode-332</guid>
      <description>&lt;p&gt;I find myself very lucky to be a software engineer. I enjoy solving problems with code, and it usually doesn't require any effort to go into "focus mode". Quite the opposite - it's sometimes hard to stop thinking about that tricky bug and close my laptop.&lt;/p&gt;

&lt;p&gt;Still, there are situations when distractions and multitasking prevent me from achieving what I want. I have a few tricks in my toolkit to restore focus and attack the problem, even if it's a tough one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the focus mode
&lt;/h2&gt;

&lt;p&gt;Focus mode is a tool to handle certain types of work. Like a hammer or a needle, it's helpful in some situations and harmful in others. &lt;strong&gt;Focus mode is never the end goal.&lt;/strong&gt; Before trying to focus, I need to figure out what and why I want to achieve with its help.&lt;/p&gt;

&lt;p&gt;To focus means to keep our full attention on one thing for a long enough period of time. I haven't met any person who doesn't know how to do it. We all constantly go in and out of focus, naturally guided by our interests and curiosity.&lt;/p&gt;

&lt;p&gt;Beyond focus, we can sometimes fall into the flow state, a highly intense and rewarding experience of full immersion in a particular activity. Mihaly Csikszentmihalyi studied the flow state his whole life and wrote &lt;a href="https://www.goodreads.com/book/show/66354.Flow" rel="noopener noreferrer"&gt;a comprehensive book&lt;/a&gt; on the subject. What's crucial for this article is that &lt;strong&gt;the flow state usually requires focus as a prerequisite&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7kp2i0qn28365i462qk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7kp2i0qn28365i462qk.png" alt="Mental state in terms of challenge level and skill level, according to Csikszentmihalyi's flow model, Wikipedia" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mental state in terms of challenge level and skill level, according to Csikszentmihalyi's flow model, &lt;a href="https://en.wikipedia.org/wiki/Flow_(psychology)" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Below I share three tricks that help me get into focus mode, but it's important to remember that they are merely techniques for occasional use. If I regularly experience difficulties with focus, I know it's time to revisit my plans. Are they aligned with my north star? Are they achievable?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was inspired by a question from one of my mentorship sessions at &lt;a href="https://adplist.org/mentors/kate-marshalkina" rel="noopener noreferrer"&gt;ADPList&lt;/a&gt;. Mentorship is a great way to explore deeper reasons behind the lack of focus. Read &lt;a href="https://kalabro.tech/where-to-find-mentor-2023/" rel="noopener noreferrer"&gt;"Where to find a mentor"&lt;/a&gt; if you are interested in this route.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Trick 1: "Is it technically possible?"
&lt;/h2&gt;

&lt;p&gt;6 am. My alarm throws me into a dark and cold Monday morning. Even my cat, who is supposed to be a nocturnal animal, is against this idea. Before I even notice it, I start looking for reasons to stay in bed. &lt;/p&gt;

&lt;p&gt;In such moments I ask myself: is it technically possible?&lt;br&gt;
Can someone like me get up at 6 am? Is it doable for a woman who went to bed at 10 pm and has scheduled some writing work before her regular working hours?&lt;/p&gt;

&lt;p&gt;In 99% of situations, the answer is yes. It's not that cold in the kitchen for me to freeze. And if it's dark, I can turn on the lights 💡&lt;/p&gt;

&lt;h2&gt;
  
  
  Trick 2: Microtask
&lt;/h2&gt;

&lt;p&gt;It's common practice to break work into small achievable chunks of work. Yet, even a well-scoped task can be hard to start. In this situation, I create &lt;strong&gt;a microtask - the first ridiculously small step&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, if I need to build a new project, a microtask can be "initialise git repository" or "print hello world on the screen". It helps to write the microtask down even if typing it will take longer than actually doing it!&lt;/p&gt;

&lt;p&gt;If it's impossible to extract a meaningful microtask, I use the &lt;strong&gt;"Do X for 30 min"&lt;/strong&gt; template.&lt;br&gt;
Let's say I want to get better at solving algorithms problems, but I don't know where to start. I put the microtask "Work on leetcode for 30 min" in the Centered app and stare at the screen for 30 min. Half an hour later, I will understand my current level much better and can create more meaningful microtasks.&lt;/p&gt;

&lt;p&gt;Microtask is similar to micromanagement. Only apply it to your own tasks when you are stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trick 3: Add flavour
&lt;/h2&gt;

&lt;p&gt;If I don't have control over what I do, I can at least control how I do it. I call it flavour. Example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What:&lt;/strong&gt; review and update legacy documentation&lt;br&gt;
&lt;strong&gt;How (adds interest flavour):&lt;/strong&gt; generate images from your documentation using AI tool&lt;br&gt;
&lt;strong&gt;How (adds challenge flavour):&lt;/strong&gt; make resulting documentation shorter, not longer&lt;br&gt;
&lt;strong&gt;How (adds value flavour):&lt;/strong&gt; pair on it with a more junior developer&lt;br&gt;
&lt;strong&gt;How (adds fun flavour):&lt;/strong&gt; work on it from your favourite café  &lt;/p&gt;

&lt;p&gt;Deciding how I will do my work sparks motivation and increases self-accountability even when I don't feel deeply connected to the end goal of the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  And many more
&lt;/h2&gt;

&lt;p&gt;While writing this post, I discovered a good list of things that help me focus. Most of them are common sense rather than tricks:&lt;/p&gt;

&lt;p&gt;🌅 Early mornings&lt;br&gt;
🕰️ Sticking to schedule&lt;br&gt;
🔏 Working in solitude&lt;br&gt;
🧘‍♀️ Keeping mind clear (journaling, meditation, exercises)&lt;br&gt;
🤝 External deadline / commitment&lt;br&gt;
👯‍♀️ Involving other people&lt;br&gt;
🎧 Music for concentration&lt;br&gt;
🧗‍♂️ Embracing a healthy dose of discomfort&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise
&lt;/h2&gt;

&lt;p&gt;We often find ourselves fully focused and dedicated when we work on interesting and challenging problems. It feels great, and we want more of that flow state.&lt;/p&gt;

&lt;p&gt;Over the years, I learned a few tricks to restore my focus. I'm sure you have your own tricks, too. Please share in comments. I'd love to learn from you!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>motivation</category>
      <category>procrastination</category>
    </item>
    <item>
      <title>The road to Software Architecture (frontend edition)</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Wed, 01 Feb 2023 08:30:43 +0000</pubDate>
      <link>https://forem.com/kalabro/the-road-to-software-architecture-frontend-edition-564o</link>
      <guid>https://forem.com/kalabro/the-road-to-software-architecture-frontend-edition-564o</guid>
      <description>&lt;p&gt;According to the &lt;a href="https://2022.stateofjs.com/en-US/opinions/#top_js_pain_points"&gt;State of JS report&lt;/a&gt;, the “Code Architecture” problem was the main pain point for JavaScript developers in 2022.&lt;/p&gt;

&lt;p&gt;In this post, I argue that folders are better than microservices, disagree with Uncle Bob, and cite Martin Fowler’s advice against the Gang Of Four book. This is my road to Software Architecture. Let’s go!&lt;/p&gt;

&lt;h2&gt;
  
  
  My background
&lt;/h2&gt;

&lt;p&gt;As a Full-Stack Developer, I’ve been involved in the software design process since very early in my career.&lt;/p&gt;

&lt;p&gt;Even before I realised it, I started making everyday architectural decisions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where to put my code&lt;/li&gt;
&lt;li&gt;what &amp;amp; how to test&lt;/li&gt;
&lt;li&gt;which framework to use&lt;/li&gt;
&lt;li&gt;how to spread the work between multiple developers, and so on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It turned out these little decisions matter in the long run. Some pieces of PHP code that I wrote eight years ago are still in use in production.&lt;/p&gt;

&lt;p&gt;The oldest React app that is currently in use was started by my team at SystemSeed in 2017 from the Create React App template. We’ve managed to stay on un-ejected CRA all these years and recently upgraded the codebase to React 18.&lt;/p&gt;

&lt;p&gt;Another long-living project was built with &lt;a href="https://vercel.com/blog/next2"&gt;Next.js 2&lt;/a&gt;. Today it runs on top of Next.js 13 and serves thousands of users around the globe.&lt;/p&gt;

&lt;p&gt;Working on such projects brings a lot of problems that I can classify as “Code Architecture” from the State of JS report. Let me elaborate on what I understand by that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software Architecture (as I understand it)
&lt;/h2&gt;

&lt;p&gt;There are many clever definitions of software architecture. In this article, I lean towards the term “software architecture” to avoid any confusion between “software design” and “UI design”.&lt;/p&gt;

&lt;p&gt;Philosophically speaking, &lt;strong&gt;software architecture work is about finding optimal answers to questions that don’t have one correct answer&lt;/strong&gt;. I mean those questions with zero answers on StackOverflow (apart from the famous “It depends”).&lt;/p&gt;

&lt;p&gt;Architectural problems often appear at the worst possible moment, disturbing our coding flow and making us feel annoyed and uncertain. That’s why software architecture can feel like a pain point, but in fact, it’s an essential part of our jobs, and Copilots can’t do it yet!&lt;/p&gt;

&lt;p&gt;Traditionally, software architecture decisions have been part of more senior roles’ responsibilities. Some companies even have a dedicated Software Architect role. That person, though, wouldn’t be able to decide on every little detail. They likely came from the backend background to oversee the systems on a very high level. So in practice, &lt;strong&gt;developers who actually implement frontend applications are the main contributors to the resulting code architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s suddenly a lot of pressure on us! Let’s see how we can reduce our anxiety around code architecture and become better at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn your tools
&lt;/h2&gt;

&lt;p&gt;“Clean Architecture”, the famous book by Uncle Bob, states that we should design framework-agnostic architectures:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Good architectures are centered on use cases so that architects can safely describe the structures that support those use cases without committing to frameworks, tools, and environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Really? Well, I’m hired as a framework specialist; how can I put it aside?&lt;/p&gt;

&lt;p&gt;The answer turned out to be simple. Before you can put the frameworks aside, you need to learn a few of them on a very good level. Once you become fluent in a couple of frameworks, you start to see patterns and trade-offs. At that point, recommendations from Uncle Bob will start to make sense.&lt;/p&gt;

&lt;p&gt;For example, these days, I focus on improving my React skills. For me, learning advanced React patterns is a valuable time investment and a good step towards understanding modern frontend in general.&lt;/p&gt;

&lt;p&gt;My decision to focus on one established technology means &lt;strong&gt;saying no to many other tools and frameworks&lt;/strong&gt; highlighted in the State of JS report. It's uncomfortable to feel "left behind," but I am confident that it will pay off.&lt;/p&gt;

&lt;p&gt;As Nathaniel Schutta says in &lt;a href="https://tanzu.vmware.com/content/ebooks/thinking-architecturally"&gt;"Thinking Architecturally"&lt;/a&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I thought I’d “missed the wave” of some technology or another. What I didn’t appreciate at the time is that new technologies are a lot like buses — one comes every 15 minutes or so.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once I understand the tool &lt;strong&gt;deeply&lt;/strong&gt;, I start making more informed architectural decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embrace folders
&lt;/h2&gt;

&lt;p&gt;Many of us jumped into microservices way too soon. There is a much safer (and cheaper) option — folders!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Folders are logical boundaries&lt;/strong&gt; of our modules, features, components, etc. Well-organised file structure makes project architecture readable and extendable.&lt;/p&gt;

&lt;p&gt;React community has a couple of suggestions to start with (&lt;a href="https://reactjs.org/docs/faq-structure.html"&gt;1&lt;/a&gt;, &lt;a href="https://github.com/alan2207/bulletproof-react"&gt;2&lt;/a&gt;). The official site says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you’re just starting a project, don’t spend more than five minutes on choosing a file structure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s not because file structure is not important. It’s because it should change as your project evolves. Let’s say you had to touch files from ten different folders to ship a new feature. It’s a sign that you need to review your folder structure (and your logical boundaries).&lt;/p&gt;

&lt;h2&gt;
  
  
  Testable code
&lt;/h2&gt;

&lt;p&gt;Most people write tests because they want to be confident that the app works as expected after code changes. As a nice bonus, &lt;strong&gt;testable code results in better code architecture&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;For a long time, I was only using end-to-end tests that treated the resulting app as a black box. It allowed me to write mediocre code with spaghetti from dependencies, inconsistencies and workarounds. Everything changed when I started to imagine how I would write other types of tests for my code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visual regression test&lt;/strong&gt; (e.g. component look &amp;amp; feel with dummy content)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit test&lt;/strong&gt; (e.g. how the utility function calculates the fee based on ordered products)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration test&lt;/strong&gt; (e.g. how the Basket component responds to user interactions such as hover and click)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end test&lt;/strong&gt; (finally, how the entire shopping flow works in the browser)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if I don’t write all these types of tests, thinking about them helps me structure my code better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about design patterns?
&lt;/h2&gt;

&lt;p&gt;Design patterns in software are similar to the chords in music. Someone discovered them many years ago, but people keep combining the chords in many different ways to compose new songs.&lt;/p&gt;

&lt;p&gt;Just like learning chords by the book may be difficult at the beginning, classic design patterns books may not make any sense for a frontend developer.&lt;/p&gt;

&lt;p&gt;A quote from Martin Fowler’s review of the famous Design Patterns book:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Despite my praise, this is not an easy book to read. I don’t recommend it until you’re pretty comfortable with the basic principles of OO design. Even then it takes a fair investment of effort to really appreciate the book. Unlike most books, however, it amply pays that investment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luckily, we can &lt;strong&gt;learn about modern JavaScript and React design patterns from a free book &lt;a href="https://www.patterns.dev/"&gt;Patterns.dev&lt;/a&gt;&lt;/strong&gt;. It describes all common patterns in a frontend-friendly language with practical examples and animations.&lt;/p&gt;



&lt;p&gt;&lt;em&gt;&lt;a href="https://www.patterns.dev/posts/observer-pattern/"&gt;Observer Pattern&lt;/a&gt; animation from patterns.dev (video)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.patterns.dev/resources/"&gt;The Community Patterns&lt;/a&gt; section lists some framework-specific resources to dig deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business logic
&lt;/h2&gt;

&lt;p&gt;The pieces of UI logic we write for the frontend may be trivial, but their large volume and constant changes become a challenge as the projects grow. The most coherent approach to business logic that I have found so far is Domain-Driven Design (DDD).&lt;/p&gt;

&lt;p&gt;DDD places a strong emphasis on building a shared understanding of the problem domain and focuses team efforts on the most important parts (“Core” subdomain).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Domain-Driven Design is about letting your business domain drive your design decisions.&lt;br&gt;&lt;br&gt;
Vlad Knononov, &lt;a href="https://a.co/d/ez4dQLr"&gt;"Learning Domain-Driven Design"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, development teams should understand and stay focused on the problem the business is trying to solve for its users.&lt;/p&gt;

&lt;p&gt;If it sounds too abstract, I recommend the “Learning Domain-Driven Design” book (&lt;a href="https://kalabro.tech/learning-domain-driven-design-book/"&gt;read my review here&lt;/a&gt;).&lt;br&gt;
I’m currently exploring ways to apply DDD principles to frontend architecture problems. Stay tuned for more articles on the topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise
&lt;/h2&gt;

&lt;p&gt;Some questions about software development don’t have one correct answer apart from “It depends”. We face them every day, and our answers contribute to the architecture of the projects we work on.&lt;/p&gt;

&lt;p&gt;Developers who know their tools and cover their code with tests tend to make better architectural decisions. That’s why I suggest starting by mastering essential frontend tooling.&lt;/p&gt;

&lt;p&gt;Once we feel comfortable with the tooling, we can zoom out and think in terms of design patterns and business problems. It’s a whole new world! I made several attempts to enter it, and I found the following resources most helpful so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.patterns.dev/"&gt;Patterns.dev&lt;/a&gt; - frontend-friendly book on design patterns&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.goodreads.com/en/book/show/39996759"&gt;“A Philosophy of Software Design”&lt;/a&gt; - my favourite software engineering book&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.amazon.com/dp/B09J2CMJZY?ref_=cm_sw_r_cp_ud_dp_WFMGPCPV66M1VA8P2CCS"&gt;Learning Domain-Driven Design&lt;/a&gt; - good introduction to DDD (&lt;a href="https://kalabro.tech/learning-domain-driven-design-book/"&gt;my review&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s how far I went on my road to Software Architecture.&lt;br&gt;&lt;br&gt;
Follow me on here on dev.to or on &lt;a href="https://twitter.com/kalabro"&gt;Twitter&lt;/a&gt; to stay updated on my next adventures.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Flutter guide for React developers</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Tue, 24 Jan 2023 08:06:39 +0000</pubDate>
      <link>https://forem.com/kalabro/flutter-guide-for-react-developers-1noh</link>
      <guid>https://forem.com/kalabro/flutter-guide-for-react-developers-1noh</guid>
      <description>&lt;p&gt;&lt;em&gt;Flutter is a popular framework for building cross-platform mobile apps. I had a chance to play with Flutter and found quite a few similarities with React. In this guide, I map common Flutter concepts to their equivalents in web development. If you are a React developer interested in Flutter, it will help you find your fit in the new territory.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article doesn’t question whether you should use Flutter, React Native, PWA or a native app approach. There are good use cases for each of them. Today we will focus on Flutter for mobile app development. Let’s dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;VS Code → VS Code&lt;/li&gt;
&lt;li&gt;Chrome Dev Tools → Flutter Dev tools&lt;/li&gt;
&lt;li&gt;TypeScript → Dart&lt;/li&gt;
&lt;li&gt;ESlint → Dart lint&lt;/li&gt;
&lt;li&gt;div → Widget&lt;/li&gt;
&lt;li&gt;CSS → Widget&lt;/li&gt;
&lt;li&gt;Accessibility → Widget (again!)&lt;/li&gt;
&lt;li&gt;@mui → Material Components (MDC)&lt;/li&gt;
&lt;li&gt;Render → Build&lt;/li&gt;
&lt;li&gt;State → State&lt;/li&gt;
&lt;li&gt;npm → pub.dev&lt;/li&gt;
&lt;li&gt;Redux + React Query → Riverpod&lt;/li&gt;
&lt;li&gt;React Router → Go Router&lt;/li&gt;
&lt;li&gt;Backend → Firebase&lt;/li&gt;
&lt;li&gt;React Testing Library → flutter_test&lt;/li&gt;
&lt;li&gt;React Docs → docs.flutter.dev&lt;/li&gt;
&lt;li&gt;What’s next&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;VS Code → VS Code&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Most Flutter developers write code with the same tools as web developers.&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.flutter.dev/development/tools/vs-code" rel="noopener noreferrer"&gt;VS Code with Flutter extension&lt;/a&gt; is the most popular option. &lt;/p&gt;

&lt;p&gt;Android Studio has first-class Flutter support if you are more comfortable with IntelliJ IDEA. I picked this option and was quite happy with it. &lt;/p&gt;

&lt;p&gt;Like any other mobile dev setup, it takes time to prepare everything for cross-platform development. To help developers troubleshoot their local setup, Flutter comes with a handy utility &lt;code&gt;flutter doctor&lt;/code&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%2Fkalabro.tech%2Fflutter-doctor-68d141b9eb946062ab1747eb6915fd49.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%2Fkalabro.tech%2Fflutter-doctor-68d141b9eb946062ab1747eb6915fd49.gif" alt="Flutter Doctor utility"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  💡 Get started with the local development environment:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Carefully follow &lt;a href="https://docs.flutter.dev/get-started/install" rel="noopener noreferrer"&gt;official installation instructions&lt;/a&gt;. Don’t skip steps! &lt;/li&gt;
&lt;li&gt;If you are not ready to install Flutter locally, you can also use &lt;a href="https://dartpad.dev/" rel="noopener noreferrer"&gt;DartPad&lt;/a&gt;, an online Dart &amp;amp; Flutter playground&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I personally found the initial installation process more straightforward than for React Native.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;Chrome Dev Tools → Flutter Dev tools&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It’s hard to imagine web development without the powerful dev tools we have in our browsers. &lt;/p&gt;

&lt;p&gt;Surprisingly, Flutter isn’t far behind. I started using Flutter widget inspector from day 1 to debug my widgets styling issues. Just like in Chrome, Flutter Inspector has multiple tabs, from Networking to Performance. It was interesting to explore my app from different angles there.&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%2Fkalabro.tech%2Fslow-animations-632df37dfa1d62289e1a299c3db52f99.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%2Fkalabro.tech%2Fslow-animations-632df37dfa1d62289e1a299c3db52f99.gif" alt="Debugging slow animations with Flutter Dev Tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last, you can debug Flutter code from your IDE using breakpoints. For some reason, I still prefer &lt;code&gt;console.log()&lt;/code&gt; in JavaScript!&lt;/p&gt;
&lt;h4&gt;
  
  
  💡 Get started with Flutter Dev tools:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.flutter.dev/development/tools/devtools/overview" rel="noopener noreferrer"&gt;DevTools&lt;/a&gt; - official documentation &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;TypeScript → Dart&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Flutter uses the Dart programming language. Dart is similar to JavaScript but with types and some nice syntax sugar on top of it. &lt;br&gt;
For example, Dart has an async functionality, but &lt;code&gt;Promises&lt;/code&gt; are called &lt;code&gt;Futures&lt;/code&gt; there. &lt;/p&gt;

&lt;p&gt;If we need an array in the JavaScript sense, in Dart, we use a List:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nav&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Home'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Furniture'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Plants'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;promoActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;'Outlet'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above is a List of Strings. The last item is only added if &lt;code&gt;promoActive&lt;/code&gt; is true. Neat!&lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started with Dart:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dart.dev/guides/language/coming-from/js-to-dart" rel="noopener noreferrer"&gt;Learning Dart as a JavaScript developer&lt;/a&gt; - half an hour, and you are ready to go!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My experience with Dart was only positive so far. You don’t need to spend time configuring TypeScript or Webpack. With Dart, everything is built-in and ready to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;ESlint → Dart lint&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Dart &amp;amp; Flutter have built-in code analysing and formatting tools. It makes it easy to learn framework best practices. I was happy with the default linters setup, but it’s possible to customise it too.&lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started with linters:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;When you start a new Flutter project, the linters should be preconfigured for you&lt;/li&gt;
&lt;li&gt;For customisation check &lt;a href="https://dart.dev/tools/linter-rules" rel="noopener noreferrer"&gt;Dart linter rules&lt;/a&gt; and &lt;a href="https://pub.dev/packages/flutter_lints" rel="noopener noreferrer"&gt;Flutter linter rules&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;div → Widget&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Everything in Flutter is a widget.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you compare them to HTML tags, Flutter widgets are usually much more specialised.&lt;/p&gt;

&lt;p&gt;For example, “to center a div” in Flutter, you use the specialised Center widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I’m centered!"&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;It takes time to get familiar with all built-in Flutter widgets. I don’t think I explored even half of them. &lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started with Widgets:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Scan through &lt;a href="https://docs.flutter.dev/development/ui/widgets" rel="noopener noreferrer"&gt;the Widget catalog&lt;/a&gt; to learn what’s available &lt;/li&gt;
&lt;li&gt;Regularly watch short &lt;a href="https://docs.flutter.dev/development/ui/widgets#widget-of-the-week" rel="noopener noreferrer"&gt;“Widget of the Week”&lt;/a&gt; videos from the official Flutter team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn’t quite enjoy Flutter’s way of passing children as properties. Personally, I find JSX syntax easier to work with. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;CSS → Widget&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Everything is a widget, remember?&lt;br&gt;&lt;br&gt;
Flutter doesn’t support CSS. Instead, all styling is handled by widgets and their properties. &lt;/p&gt;

&lt;p&gt;Let’s say I want to add some padding to my Center widget. In Flutter, I need to wrap my widget with another one, specialised in padding, and pass my original widget via child property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Padding(
   padding: EdgeInsets.all(16),
   child: Center(child: Text("I’m centered!")),
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;EdgeInsets.all(16)&lt;/strong&gt;  means &lt;strong&gt;padding: 16px&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Flutter operates in logical pixels and takes care of translating our values into physical pixels for each device and screen type. &lt;/p&gt;

&lt;p&gt;Now let’s add a black border with border radius around the previous widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;DecoratedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;border:&lt;/span&gt; &lt;span class="n"&gt;Border&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;black&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I’m centered!"&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;In Flutter, all properties are granularly typed, and for each aspect of styling, you need to create a value of the appropriate type. Because of that, the resulting code is much more verbose.&lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started with Widgets:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Scan through &lt;a href="https://docs.flutter.dev/development/ui/widgets" rel="noopener noreferrer"&gt;the Widget catalog&lt;/a&gt; to learn what’s available &lt;/li&gt;
&lt;li&gt;Regularly watch short &lt;a href="https://docs.flutter.dev/development/ui/widgets#widget-of-the-week" rel="noopener noreferrer"&gt;“Widget of the Week”&lt;/a&gt; videos from the official Flutter team.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=GXIJJkq_H8g&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;How to choose which Flutter Animation Widget is right for you?&lt;/a&gt; - great overview of Flutter animations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;Accessibility → Widget (again!)&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Accessibly is a first-class citizen in Flutter. For example, images and icons have the &lt;code&gt;semanticLabel&lt;/code&gt; property for screen readers. For more advanced cases, there is a special widget &lt;code&gt;Semantics&lt;/code&gt; which has more than 50 properties to describe the meaning of your widgets.&lt;/p&gt;

&lt;p&gt;The Flutter team made it easy for developers to debug accessibility by providing the &lt;code&gt;showSemanticsDebugger&lt;/code&gt; property. It replaces the original widgets with the corresponding semantic labels that the screen readers would read:&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%2Fkalabro.tech%2Fstatic%2Fe4273e125d93bf4a11322c04d6b72a74%2F1342d%2Faccessibility.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%2Fkalabro.tech%2Fstatic%2Fe4273e125d93bf4a11322c04d6b72a74%2F1342d%2Faccessibility.png" alt="Accessibility"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started with accessibility:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.flutter.dev/development/ui/widgets/accessibility" rel="noopener noreferrer"&gt;Accessibility widgets&lt;/a&gt; - official documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;@mui → Material Components (MDC)&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;@mui is Material Design implementation for React. When using @mui as your component library, you first create a top-level theme, expose it via React Context, and then enjoy consistent styling across all your components. &lt;/p&gt;

&lt;p&gt;Below is how you would print a heading with @mui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Typography&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h4"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Heading 4&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Typography&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flutter comes with Material Components (MDC) out of the box. Technically you can opt-out and go your own way, but I haven’t explored that route yet.&lt;/p&gt;

&lt;p&gt;Similar to React implementation, various aspects of the theme are first configured at the top level of the app and then reused in individual widgets like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;'Heading 4'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textTheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headline4&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;h4&gt;
  
  
  💡 Get started with Material:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.flutter.dev/codelabs" rel="noopener noreferrer"&gt;MDC codelabs&lt;/a&gt; (small practical lessons) from the official Flutter team&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://m3.material.io/theme-builder#/custom" rel="noopener noreferrer"&gt;Material Theme Builder&lt;/a&gt; supports export in Flutter&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/flutter/material-3-for-flutter-d417a8a65564" rel="noopener noreferrer"&gt;Material 3 for Flutter&lt;/a&gt; by Eilidh Southren&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://rydmike.com/blog_theming_guide" rel="noopener noreferrer"&gt;Flutter Theming Guide&lt;/a&gt; by Mike Rydstrom&lt;/li&gt;
&lt;/ul&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%2Fkalabro.tech%2Fstatic%2F03f9d1b2d96531675cc1e7c6c4b25762%2F16cb4%2Fmaterial-builder.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%2Fkalabro.tech%2Fstatic%2F03f9d1b2d96531675cc1e7c6c4b25762%2F16cb4%2Fmaterial-builder.png" alt="Material Theme Builder supports export in Flutter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be prepared for a steep learning curve: hundreds of widgets and properties, sophisticated Material theme configuration, and of course, mobile device specifics that don’t exist on the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;Render → Build&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Flutter widgets are classes that must implement the build method. It’s similar to the render method in React class components.&lt;/p&gt;

&lt;p&gt;Let’s implement the build method for our “centered div” example from the beginning of this guide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CenteredText&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;CenteredText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="c1"&gt;// Props are class members in Flutter.&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Widget must implement the build method.&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&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;If you had a negative experience with class components in React, put it aside for a moment. Flutter is based on Dart, and its class implementation is much more robust and well-thought than in JavaScript. &lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started with building custom widgets:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=wE7khGHVkYY&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;How to Create Stateless Widgets&lt;/a&gt; from Flutter in Focus video series&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;State → State&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Quote from Flutter documentation: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Flutter widgets are built using a modern framework &lt;strong&gt;that takes inspiration from React&lt;/strong&gt;. The central idea is that you build your UI out of widgets. Widgets describe what their view should look like given their current configuration and state. When a widget’s state changes, the widget rebuilds its description, which the framework diffs against the previous description in order to determine the minimal changes needed in the underlying render tree to transition from one state to the next.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The actual implementation of stateful widgets differs from how we build stateful components in React. Instead of adding one line of code with the &lt;code&gt;useState&lt;/code&gt; hook, you need to create two (!) separate objects: one for the stateful widget and another for its state. Wonder why? Check out the links below for details.&lt;/p&gt;

&lt;p&gt;Luckily, both VS Code and Android Studio have shortcuts to scaffold Flutter widgets. In practice, I can create Flutter widgets as fast as I create new React components.&lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started with stateful widgets:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=AqCMFXEmf3w&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;How Stateful Widgets Are Used Best&lt;/a&gt; from Flutter in Focus video series &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://iiro.dev/set-state/" rel="noopener noreferrer"&gt;Flutter’s setState() might not be what you think it is&lt;/a&gt; - Flutter is inspired by React, but under the hood, it works differently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;npm → pub.dev&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pub.dev/" rel="noopener noreferrer"&gt;pub.dev&lt;/a&gt; is the official package repository for Dart and Flutter apps. I found it very clean and developer-friendly. &lt;br&gt;
Pub.dev promotes high-quality packages via the &lt;a href="https://docs.flutter.dev/development/packages-and-plugins/favorites" rel="noopener noreferrer"&gt;Flutter Favorite&lt;/a&gt; program and &lt;a href="https://www.youtube.com/playlist?list=PLjxrf2q8roU1quF6ny8oFHJ2gBdrYN_AK" rel="noopener noreferrer"&gt;Package of the Week&lt;/a&gt; YouTube show.&lt;/p&gt;

&lt;p&gt;There are two files in the Flutter app directory that are related to pub.dev: pubspec.yaml and pubspec.lock (equivalents of package.json and package.lock).&lt;/p&gt;
&lt;h4&gt;
  
  
  💡 Get started with pub.dev:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Head to &lt;a href="https://pub.dev/" rel="noopener noreferrer"&gt;pub.dev&lt;/a&gt; and explore the packages&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;Redux + React Query → Riverpod&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Like with React, the Flutter ecosystem has born a dozen competing state managers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/RydMike/status/1578462043593535488" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkalabro.tech%2Fstatic%2Fc9750c881059d251389cf78358481caf%2F16cb4%2Ftop30-state-managers.png" alt="TOP 30 Flutter State packages by Mike Rydstrom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some seasoned Flutter developers lean towards Riverpod (#5 in the chart above) when building real, complex applications. I trust their choice.&lt;/p&gt;
&lt;h4&gt;
  
  
  💡 Get started with Riverpod:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://codewithandrea.com/articles/flutter-state-management-riverpod/" rel="noopener noreferrer"&gt;Flutter Riverpod 2.0: The Ultimate Guide&lt;/a&gt; by Andrea Bizzotto&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/bizz84/starter_architecture_flutter_firebase" rel="noopener noreferrer"&gt;Time Tracking app with Flutter &amp;amp; Firebase&lt;/a&gt; - an example app by Andrea Bizzotto&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;React Router → Go Router&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Mobile app navigation is quite different from the web. The built-in Flutter Navigation API is so complex that the Flutter team decided to build an official third-party package with a simpler API: Go Router.&lt;/p&gt;

&lt;p&gt;Similar to React Router, you declare your routes (and their sub-routes) and map them to the screens of your app.&lt;/p&gt;

&lt;p&gt;Get started with Go Router:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://codewithandrea.com/articles/flutter-navigation-gorouter-go-vs-push/" rel="noopener noreferrer"&gt;Flutter Navigation with GoRouter: Go vs Push&lt;/a&gt; by Andrea Bizzotto&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.flutter.dev/development/ui/navigation/deep-linking" rel="noopener noreferrer"&gt;Deep linking&lt;/a&gt; - official Flutter documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;Backend → Firebase&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Mobile/desktop apps are rarely static landing pages. Almost always they require some backend for authentication, data synchronisation, analytics and more. Yet most apps will never become popular, and developers don’t want to spend months building sophisticated backends. That’s why Firebase is so popular in mobile dev, Flutter included. It offers a set of APIs for all common features you may need as a mobile developer, all free until a certain threshold. &lt;/p&gt;

&lt;p&gt;Google supports both Flutter and Firebase so you can expect an excellent integration between the two. If you don’t want to store your data with Google, several open source alternatives provide similar developer experience.&lt;/p&gt;
&lt;h4&gt;
  
  
  💡 Get started with Firebase:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://firebase.google.com/docs/flutter/setup" rel="noopener noreferrer"&gt;Add Firebase to your Flutter app&lt;/a&gt; - official documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dartpad.dev/?id=d57c6c898dabb8c6fb41018588b8cf73" rel="noopener noreferrer"&gt;One-file Firebase chat app&lt;/a&gt; - official DartPad example&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=SXmYUalHyYk&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;I tried 5 Firebase alternatives&lt;/a&gt; - video by Jeff Delaney&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;React Testing Library → flutter_test&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A robust testing ecosystem is another sign of a serious approach to the framework quality. &lt;/p&gt;

&lt;p&gt;Developers can test Flutter apps with the following types of tests:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Unit&lt;/strong&gt; — verifies the behaviour of a method or class&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Widget&lt;/strong&gt; — verifies the behaviour of Flutter widgets without running the app itself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Golden&lt;/strong&gt; — verifies visual output of Flutter widgets without running the app itself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI integration&lt;/strong&gt; — verifies the full app UI works by running the app on a device (some network services can be mocked)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end&lt;/strong&gt; — same as above, but without any mocking&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example of a widget test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;testWidgets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Testing MyWidget'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WidgetTester&lt;/span&gt; &lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pumpWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyWidget&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Save'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pump&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Success'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;findsOneWidget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;WidgetTester&lt;/code&gt; provides an API to manipulate widgets programmatically; for example, &lt;code&gt;tester.tap(find.text('Save'))&lt;/code&gt; will simulate tapping on the “Save” button.&lt;/p&gt;

&lt;p&gt;It was pretty unexpected for me to find &lt;a href="https://api.flutter.dev/flutter/flutter_test/matchesGoldenFile.html" rel="noopener noreferrer"&gt;visual regression testing tools&lt;/a&gt; (Golden image tests) in the standard testing library. In addition to the standard tools, there are several external packages that help to further advance Flutter testing.&lt;/p&gt;

&lt;h4&gt;
  
  
  💡 Get started:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.flutter.dev/testing" rel="noopener noreferrer"&gt;Testing Flutter apps&lt;/a&gt; - official documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/packages/golden_toolkit" rel="noopener noreferrer"&gt;Golden Toolkit&lt;/a&gt; - UI regression tests on top of Flutter’s Golden test functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;React Docs → docs.flutter.dev&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Official Flutter and Dart documentation are exceptionally good. Apart from detailed written documentation, the Flutter team provides interactive examples, videos, and codelabs.&lt;/p&gt;

&lt;p&gt;You may not need any paid external resources &lt;em&gt;at all&lt;/em&gt; to become a Flutter dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;br&gt;&lt;br&gt;What’s next&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I hope this guide will help you navigate the Flutter world as a React developer. If you are at the very beginning, start with &lt;a href="https://docs.flutter.dev/codelabs" rel="noopener noreferrer"&gt;“Your first Flutter app” codelab&lt;/a&gt;. Feel free to bookmark this guide and return to it as you progress through your journey!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>My approach to the command line</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Mon, 10 May 2021 14:31:58 +0000</pubDate>
      <link>https://forem.com/kalabro/my-approach-to-the-command-line-1kfm</link>
      <guid>https://forem.com/kalabro/my-approach-to-the-command-line-1kfm</guid>
      <description>&lt;p&gt;There is an idea that every developer should master tons of sophisticated tools and keyboard shortcuts to be truly professional and efficient. &lt;/p&gt;

&lt;p&gt;My experience doesn't confirm it. As an example, let me show you my command line setup. I'm not a sysadmin, but as a full stack developer with 10+ years of experience I use the terminal on a daily basis yet I've got a very basic setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No tmux&lt;/li&gt;
&lt;li&gt;No aliases&lt;/li&gt;
&lt;li&gt;No special .dotfile configs&lt;/li&gt;
&lt;li&gt;No shell preference. I'm fine with zsh, bash, ksh, etc&lt;/li&gt;
&lt;li&gt;No jokes on how to quit vim 🔫&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My favourite terminal shortcuts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ctrl+R to explore the history&lt;/li&gt;
&lt;li&gt;Ctrl+C to cancel / cleanup current command&lt;/li&gt;
&lt;li&gt;Ctrl+L to clean the screen&lt;/li&gt;
&lt;li&gt;Ctrl+A / Ctrl+E to jump to the beginning / end of the command string&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My top-used commands
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;git&lt;/li&gt;
&lt;li&gt;j (&lt;a href="https://github.com/wting/autojump"&gt;smart &lt;code&gt;cd&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;make&lt;/li&gt;
&lt;li&gt;ls&lt;/li&gt;
&lt;li&gt;rm&lt;/li&gt;
&lt;li&gt;cat&lt;/li&gt;
&lt;li&gt;grep&lt;/li&gt;
&lt;li&gt;vi&lt;/li&gt;
&lt;li&gt;yarn, npm, npx, composer, docker-compose and other project-specific CLI tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can grab your most used commands too: &lt;a href="https://superuser.com/questions/250227/how-do-i-see-what-my-most-used-linux-command-are"&gt;How do I see what my most used linux command are?&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I stick to defaults
&lt;/h2&gt;

&lt;p&gt;Apart from &lt;a href="https://github.com/wting/autojump"&gt;autojump&lt;/a&gt;, everything else in my setup is quite basic. I try to stick to defaults as much as possible. This is why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common use cases are easy to google.&lt;/strong&gt;&lt;br&gt;
StackOverflow is full of advice on how to do X, Y, Z in the terminal. In 99% of the cases the solution will use standard tools that are already available on my machine: &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;chmod&lt;/code&gt;, etc. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-standard tools require installation.&lt;/strong&gt;&lt;br&gt;
If I make &lt;a href="https://github.com/BurntSushi/ripgrep"&gt;&lt;code&gt;rg&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://github.com/ggreer/the_silver_searcher"&gt;&lt;code&gt;ag&lt;/code&gt;&lt;/a&gt; my default search tool, I'll have to install it on the remote servers, in the CI environments, in the cloud IDEs, on my colleagues' machines. It's not always possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customisation requires more learning and memorising.&lt;/strong&gt;&lt;br&gt;
Now I need to learn how to use both the new tool (let's say &lt;code&gt;ag&lt;/code&gt;) and the standard pre-installed tool (usually &lt;a href="https://linuxjourney.com/lesson/grep-command"&gt;&lt;code&gt;grep&lt;/code&gt;&lt;/a&gt;). Otherwise, I won't be able to work in remote environments, help a teammate (or receive help from them), debug a CI script, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updates and troubleshooting.&lt;/strong&gt;&lt;br&gt;
Custom setup can become outdated, can introduce bugs or security issues. I can simply forget that I installed a tricky git helper a year ago and it will cost me a day of troubleshooting at some point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn the basics and have fun!
&lt;/h2&gt;

&lt;p&gt;Most of the modern development stacks assume basic command line knowledge. The keyword is &lt;em&gt;basic&lt;/em&gt;: you don't need to make Vim your default text editor or master tmux to become a better developer. If you normally spend 30% of your time in, let's say, Chrome DevTools and another 30% in VS Code, then you'd better master Chrome DevTools and VS Code first.&lt;/p&gt;

&lt;p&gt;As a developer and Tech Lead, I think of the terminal mastering as something extra that I'm free to do if I &lt;em&gt;want&lt;/em&gt;. After all, it can be a lot of fun! But I don't have to be a command line geek, and you don't have to either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question for you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is your favourite CLI command or shortcut?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mine is &lt;code&gt;Ctrl+R&lt;/code&gt; to search through my command line history. This is how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hit &lt;code&gt;Ctrl+R&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Start typing any part of the previous command you want to run again, e.g. &lt;code&gt;exec&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You command line will be prepopulated with the most recent command that contained &lt;code&gt;exec&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If it's not the right one, hit &lt;code&gt;Ctrl+R&lt;/code&gt; again to cycle through older commands.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>linux</category>
      <category>terminal</category>
      <category>bash</category>
      <category>productivity</category>
    </item>
    <item>
      <title>3 simple management tricks I learned as a Tech Lead</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Thu, 08 Apr 2021 07:39:42 +0000</pubDate>
      <link>https://forem.com/kalabro/3-simple-management-tricks-i-learned-as-a-tech-lead-4apn</link>
      <guid>https://forem.com/kalabro/3-simple-management-tricks-i-learned-as-a-tech-lead-4apn</guid>
      <description>&lt;p&gt;Developers often blame "bad management" when something goes wrong. I've been there too, I remember the pain. &lt;/p&gt;

&lt;p&gt;For me, it was useful to sit on both chairs for a while acting as a Tech Lead. In this article, I share three dead simple tricks everyone can start using now to become better managers for themselves. No MBA required 🤓&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Repeat (say it again)
&lt;/h2&gt;

&lt;p&gt;Yes, the tricks will be very simple, even stupid, but they work! One of my favourites is repeating. It's a very powerful yet underestimated technique. &lt;/p&gt;

&lt;p&gt;Finding the courage to say something once is hard, especially when the topic is important to you.  But don't stop there! People forget, deprioritise and misunderstand all the time. &lt;/p&gt;

&lt;p&gt;Internet is full of advice on how to say No, which implies that everything has to be said at least twice. Camille Fournier actually suggests you need to say it three times:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Finally, never underestimate how many times and how many ways something needs to be said before it sinks in. Communication in a large organization is hard. In my experience, most people need to hear something at least three times before it really sinks in.&lt;br&gt;
&lt;a href="https://www.amazon.com/dp/B06XP3GJ7F/ref=cm_sw_em_r_mt_dp_MKXET9C33MXQ4TEVK3NG"&gt;The Manager's Path, Camille Fournier&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some examples where repeating is useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remind about an ongoing problem if it was deprioritised.&lt;/li&gt;
&lt;li&gt;Talk to someone else if the first contacted person wasn't helpful. &lt;/li&gt;
&lt;li&gt;Insist on prioritising some refactoring or housekeeping work.&lt;/li&gt;
&lt;li&gt;Rephrase technical concept in plain English.&lt;/li&gt;
&lt;li&gt;Keep pointing out the agreed coding practices until they are being followed.&lt;/li&gt;
&lt;li&gt;Thank teammates for their help, again and again, in different ways.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some channels may overuse repetition (e.g. TV series or popular non-fiction). It annoys us and we may think that saying the same thing multiple times is rude or dull. From my experience, if you are respectful and creative, everyone will appreciate your persistence. &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Write full sentences (overcommunicate)
&lt;/h2&gt;

&lt;p&gt;Remote work involves a lot of written communication via email and chat apps. Make your written communication explicit and straight to the point so that people don't have to read 50 chat messages and two different Jira tickets to understand your last "@channel" message in Slack.&lt;/p&gt;

&lt;p&gt;Two ways of saying "No update yet" about the hosting incident:&lt;/p&gt;

&lt;p&gt;✅ &lt;br&gt;
&lt;em&gt;No update yet. I'm checking with Mike from DevOps team about the issue with &lt;a href="http://www.example.com"&gt;www.example.com&lt;/a&gt; deployment. I will come back to you in 15 min.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;❌ &lt;br&gt;
&lt;em&gt;No update yet. I'll check with Mike about that issue.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;(Who is Mike? Which issue? When will you check? When will my site go up!?)&lt;/p&gt;

&lt;p&gt;Again, over-communication isn't rude, it's really the opposite. If something is obvious to you (e.g. there is an ongoing issue with &lt;a href="http://www.example.com"&gt;www.example.com&lt;/a&gt; ), it doesn't mean it's obvious to everyone else. Give them the necessary context as part of your text message, and you'll get meaningful responses faster. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Take care of yourself
&lt;/h2&gt;

&lt;p&gt;If I would need to limit this article to only one piece of advice, I would keep this one.&lt;/p&gt;

&lt;p&gt;You know better than anyone else when you are stuck or bored or confused. It's very normal and it happens to all of us from time to time. Take action to get yourself out of it. If we all as individuals will take care of ourselves, many problems will be resolved much quicker and easier. Uncommunicated problems create more problems.&lt;/p&gt;

&lt;p&gt;Your manager may catch some signals of your burnout when it's too late. Help them and ask for a break sooner. &lt;/p&gt;

&lt;p&gt;Your boss may have no idea that you want to leave the company because you hate DevOps work. Help them and ask for more frontend work in the upcoming project. &lt;/p&gt;

&lt;p&gt;Your client has no idea that you are a morning person. Help them and ask to move late meetings earlier in the day. Repeat if it didn't work from the first time 😃&lt;/p&gt;

&lt;p&gt;There is no point in struggling at work. Happy people deliver better results, but what is more important, they make other people happier. &lt;/p&gt;

&lt;p&gt;Hopefully, these simple tricks will make you a bit happier at work too! &lt;/p&gt;

</description>
      <category>career</category>
      <category>softskills</category>
      <category>management</category>
    </item>
    <item>
      <title>“Just for fun” coding resources / ideas?</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Fri, 14 Aug 2020 21:00:03 +0000</pubDate>
      <link>https://forem.com/kalabro/just-for-fun-coding-resources-ideas-4kl</link>
      <guid>https://forem.com/kalabro/just-for-fun-coding-resources-ideas-4kl</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@ryanquintal?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Ryan Quintal&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;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi DEV!&lt;/p&gt;

&lt;p&gt;Could you recommend any ideas/frameworks/games for “Just for fun” coding?&lt;/p&gt;

&lt;p&gt;In my normal Tech Lead role, &lt;strong&gt;I miss coding a lot&lt;/strong&gt;, so I decided to spend some time next week coding just for fun. Not reading too much, not configuring servers too much, not promoting or selling the product — &lt;strong&gt;just good old code stuff!&lt;/strong&gt; 💻🥳&lt;/p&gt;

&lt;p&gt;I mainly worked with Next.js and PHP (it was the main tech for building web sites when I started 👵), but have touched a bit of everything.&lt;/p&gt;

&lt;p&gt;What would be your advice? &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>fun</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Let Cloudflare CDN speed up your classic website like it's static</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Sat, 08 Aug 2020 15:29:23 +0000</pubDate>
      <link>https://forem.com/kalabro/let-cloudflare-cdn-speed-up-your-classic-website-like-it-s-static-oaf</link>
      <guid>https://forem.com/kalabro/let-cloudflare-cdn-speed-up-your-classic-website-like-it-s-static-oaf</guid>
      <description>&lt;p&gt;One obvious strength of static sites is their performance. The pages aren't generated by the server but instead pre-built into HTML &amp;amp; CSS files.&lt;/p&gt;

&lt;p&gt;Many of us developers have already played with the technology, built &lt;a href="https://www.staticgen.com/"&gt;their own static site generator&lt;/a&gt; and learned the pros &amp;amp; cons of this approach. I won't discuss all of that in this article. Instead, I will remind ourselves of something else that's been there for years — CDN.&lt;/p&gt;

&lt;p&gt;These days CDN setup should not necessarily be very complicated and enterprisy. In fact, I will be using free Cloudflare tier in my examples. Other CDNs have the same or similar setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;When your web server returns a page, let's say "&lt;a href="https://www.mozilla.org/en-GB/"&gt;https://www.mozilla.org/en-GB/&lt;/a&gt;", it also returns &lt;code&gt;Cache-Control&lt;/code&gt; header explaining to the external world how to cache this specific page. For example, it can say "do not cache me at all" or "cache me for an hour", please.&lt;/p&gt;

&lt;p&gt;Browsers and CDNs respect &lt;code&gt;Cache-Control&lt;/code&gt; header when they serve web pages. If the page can be cached, they save it in their cache storage and next time serve cached version without ever touching your web server. That's how a dynamic WordPress site can behave like static for the entirety of anonymous users.&lt;/p&gt;

&lt;p&gt;Let's have a look at &lt;a href="https://www.mozilla.org/en-GB/:"&gt;https://www.mozilla.org/en-GB/:&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yW4X5aAi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/baa74ca45e2a7ef0cf95d6a1d1ac8d33/b69cc/cdn-mozilla.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yW4X5aAi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/baa74ca45e2a7ef0cf95d6a1d1ac8d33/b69cc/cdn-mozilla.jpg" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTTP status of the page is 200 meaning that this page was not cached in user's browser yet.&lt;/li&gt;
&lt;li&gt;Mozilla.org server returned &lt;code&gt;cache-control: max-age=600&lt;/code&gt;, which means "Hey, browsers and CDNs: cache this page for 10 min max."&lt;/li&gt;
&lt;li&gt;Cloudflare CDN indeed has already cached this page (HIT)&lt;/li&gt;
&lt;li&gt;I've got a cached version which is 96 seconds old.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If within those 96 seconds something has changed on that page, e.g. a typo has been fixed, then I will still see the outdated version for the next 504 seconds. &lt;br&gt;
To avoid the page with typo to be served from CDN cache, developers from Mozilla can either flush CDN cache from Cloudflare admin UI or by using their API.&lt;/p&gt;

&lt;p&gt;Now let's dig into the details.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enabling cache beyond static files in Cloudflare
&lt;/h2&gt;

&lt;p&gt;This step will vary for each CDN service. In Cloudflare, you need&lt;br&gt;
to create so-called "Page Rule" that will enable "Cache Everything" mode for specified page pattern. Example below: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S84PM3tW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/32a57c1bd30130d64826a812e979e2c4/bfd7d/cdn-cloudflare-cache-everything-page-rule.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S84PM3tW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/32a57c1bd30130d64826a812e979e2c4/bfd7d/cdn-cloudflare-cache-everything-page-rule.jpg" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Apply this rule to the entire domain&lt;/li&gt;
&lt;li&gt;(Optional) Switch off "Always Online" feature in favour of &lt;code&gt;stale-if-error&lt;/code&gt; (will be discussed below)&lt;/li&gt;
&lt;li&gt;Cache everything (as opposed to caching &lt;a href="https://support.cloudflare.com/hc/en-us/articles/200172516-Understanding-Cloudflare-s-CDN#h_a01982d4-d5b6-4744-bb9b-a71da62c160a"&gt;only certain file extensions&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;(My favourite one) Respect "Cache-Control" header from my web server (also known as "Origin").&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that I asked Cloudflare to follow &lt;code&gt;Cache-Control&lt;/code&gt; directives returned by my web server.&lt;br&gt;
It gives me unlimited flexibility in configuring caching TTL for different pages. &lt;br&gt;
In the following section, we will discuss it further. For now, I have to add that in addition to item 4 you need to configure "Browser Cache TTL" setting in Cloudflare to "Respect Existing Headers". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A9go68zf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/944d66419a04716b02bb2aee07fbf65f/94461/cdn-cloudflare-respect-origin-cache-control.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9go68zf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/944d66419a04716b02bb2aee07fbf65f/94461/cdn-cloudflare-respect-origin-cache-control.png" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't want to mess with &lt;code&gt;Cache-Control&lt;/code&gt; in your codebase, you can ignore item 4 and "Browser Cache TTL" setting completely. Cloudflare will add &lt;code&gt;Cache-Control&lt;/code&gt; header for you anyway and you will be able to fine-tune it by "Page Rules".&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding Cache-Control header to your dynamic content
&lt;/h2&gt;

&lt;p&gt;In my experience different site pages and query params may have different cacheability opportunities.&lt;br&gt;
Think of it as if parts of your site are completely static and others are very dynamic.&lt;br&gt;
With &lt;code&gt;Cache-Control&lt;/code&gt; you can achieve this behaviour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    server.get('*', (req, res) =&amp;gt; {
      if (
        // Allow to bypass CDN cache by adding ?bypass=cdn to URL.
        req.query.bypass === 'cdn'
      ) {
        res.setHeader(
          'Cache-Control', 'no-store, must-revalidate'
        );
      } else {
        res.setHeader(
          'Cache-Control',
          'public, max-age=0, s-maxage=3600, stale-if-error=3600, stale-while-revalidate=30',
        );
      }
      return handler(req, res, app);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above is a simplified Express handler to vary caching behaviour based on the incoming request.&lt;br&gt;
You can achieve something similar in any popular web framework.&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;Cache-Control&lt;/code&gt; directive is a bit more advanced in my example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;max-age=0&lt;/code&gt; - do NOT cache on a browser level&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s-maxage=3600&lt;/code&gt; - cache on CDN (shared cache) for an hour&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stale-if-error=3600&lt;/code&gt; - serve stale cached version for one hour more if the origin server is not available (supported by some CDNs)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stale-while-revalidate=30&lt;/code&gt; - serve stale version while the new version is being fetched from the origin server (supported by some CDNs)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can build your version of &lt;code&gt;Cache-Control&lt;/code&gt; that will serve your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invalidating cache
&lt;/h2&gt;

&lt;p&gt;In the case of a static site, you need to re-build and re-upload assets to your server.&lt;br&gt;
Some services automate this process so that content editors don't have to deal with it.&lt;/p&gt;

&lt;p&gt;We have a similar situation with CDN cache: if you want the newer version of the page to become available to the rest of the world &lt;em&gt;right now&lt;/em&gt;, then you need to invalidate the existing cache.&lt;br&gt;
Cloudflare users can do it either in admin UI or via API.&lt;/p&gt;

&lt;p&gt;If you use CMS e.g. &lt;a href="https://wordpress.org/plugins/cloudflare/"&gt;Wordpress&lt;/a&gt; or &lt;a href="https://www.drupal.org/project/cloudflare"&gt;Drupal&lt;/a&gt;, they may have plugins for automated cache invalidation. &lt;/p&gt;

&lt;p&gt;Otherwise, you can call Cloudflare API directly in the appropriate place of your codebase.&lt;br&gt;
The most used API endpoint is &lt;a href="https://api.cloudflare.com/#zone-purge-files-by-url"&gt;&lt;code&gt;POST zones/:identifier/purge_cache&lt;/code&gt;&lt;/a&gt; - purges cache for specific URLs. &lt;/p&gt;

&lt;p&gt;Note that Cloudflare doesn't offer cache purging by wildcard. There is "Cache Tags" feature on Enterprise tier but I have never used it.&lt;/p&gt;

&lt;p&gt;Other CDNs offer cache purging via API too. For example, Fastly has &lt;a href="https://docs.fastly.com/en/guides/soft-purges"&gt;soft purging&lt;/a&gt; in addition to hard purging. This is something I miss in Cloudflare API. Let's say I updated content page in my CMS and it automatically purged cache for some URLs that were affected by my update. If I managed to break the site with my update, then purged URLs will be down for all anonymous users.&lt;br&gt;
With soft purge + &lt;code&gt;stale-if-error&lt;/code&gt; you could stay always online.&lt;/p&gt;

&lt;p&gt;Alternately to automated cache purging, you can just keep cache TTL very short (10 mins like in Mozilla example) instead of triggering automated cache invalidation on every content change. &lt;/p&gt;

&lt;h2&gt;
  
  
  stale-if-error or Always Online
&lt;/h2&gt;

&lt;p&gt;As you may remember, I suggested to switch off Cloudflare's "Always Online" feature (which is often enabled by default) in favour of &lt;code&gt;stale-if-error&lt;/code&gt;. &lt;code&gt;stale-if-error&lt;/code&gt; isn't noticeable for the end users while "Always Online" adds Cloudflare banner at the top of your web page informing your users that the site isn't working at the moment. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;stale-if-error&lt;/code&gt; is a standard &lt;code&gt;Cache-Control&lt;/code&gt; directive that is supported by other CDNs as well. &lt;br&gt;
It asks CDNs and browsers to serve stale cache if the page isn't available on the origin web server. Different CDNs can understand page availability differently. For example, Cloudflare will respond with stale content only to the specific error codes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z1RtgNqh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/9acae335ca14d46dd3989224ad8755e8/8c176/cdn-cloudflare-error-codes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z1RtgNqh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kalabro.tech/static/9acae335ca14d46dd3989224ad8755e8/8c176/cdn-cloudflare-error-codes.png" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;500 or 503 error codes trigger neither Always Online nor &lt;code&gt;stale-if-error&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarize
&lt;/h2&gt;

&lt;p&gt;Modern CDNs (and HTTP) provide a simple and elegant way to make parts of your site behave like they are static. CDN cache protects the site from traffic spikes and makes some of the site errors and instabilities invisible for end users. It's not just for heavy&lt;br&gt;
enterprises. A mid-size website can save computing costs of their hosting by enabling CDN cache for the most popular site pages.&lt;/p&gt;

&lt;p&gt;Of course, you should still work on the performance of the original site but CDN cache can be  nice low-hanging fruit in your journey 🍒&lt;/p&gt;

</description>
      <category>performance</category>
      <category>cdn</category>
      <category>cloudflare</category>
    </item>
    <item>
      <title>How to investigate technical solutions</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Sat, 23 May 2020 19:30:00 +0000</pubDate>
      <link>https://forem.com/kalabro/how-to-investigate-technical-solutions-5gmj</link>
      <guid>https://forem.com/kalabro/how-to-investigate-technical-solutions-5gmj</guid>
      <description>&lt;p&gt;In my &lt;a href="https://kalabro.tech/mental-health-full-stack-developers/"&gt;previous post on the subject&lt;/a&gt; I suggested the long term approach to the learning problem: focus on general knowledge rather than on specific tools and implementations. But what if you need to investigate a new technical field &lt;em&gt;right now&lt;/em&gt;, let's say this week, to proceed with the project at hand? Tech leads do this kind of work regularly in order to prepare high-level estimates and architect new systems.  &lt;/p&gt;

&lt;p&gt;In this article, I will share my approach to a quick technical investigation. I apply it to new technologies and any other unknowns as they appear in my daily tasks. I mapped the steps to the days of the week, but the timeline can be scaled up or down based on the size of the problem. So, let's get started:&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Monday
&lt;/h2&gt;

&lt;h4&gt;
  
  
  😍 You are great
&lt;/h4&gt;

&lt;p&gt;It's totally fine to not know something. Don't treat it as your “fault” or a lack of talent/education/seniority. You are going to figure it out and you are great! &lt;/p&gt;

&lt;h4&gt;
  
  
  🔍 Be specific
&lt;/h4&gt;

&lt;p&gt;Narrow down the area of investigation as much as possible. In practice, it means that technical investigation starts with business investigation. When the problem is defined, ensure you can't solve it without further investigation. Sometimes people ask for AI, but their problem can be solved with a regular expression. Stop thinking that your solution isn't “cool” enough. It's super cool as long as it solves the problem.&lt;/p&gt;

&lt;h4&gt;
  
  
  🙋‍♀️ Ask people
&lt;/h4&gt;

&lt;p&gt;If you need to proceed with further investigation, then first ask your colleagues and friends who were working on something similar in the past (don't confuse friends and colleagues with random strangers on the internet!). There is no point in learning something the hard way if you can just ask your teammate for help. An extreme variant of this option is to hire a person who has the necessary experience and learn from them.&lt;/p&gt;

&lt;h4&gt;
  
  
  📝 Pick 10 random articles
&lt;/h4&gt;

&lt;p&gt;Google your problem definition using different wording and pick 10 random articles and videos (it also can be one &lt;em&gt;short&lt;/em&gt; book). List them in your notes and start reading them all from top to the bottom. Don't try to figure out your final solution, don't make any decisions just yet, don't try code snippets suggested in the articles. Just read them.&lt;/p&gt;

&lt;p&gt;Keep reading and taking quick notes. It can be a simple bullet list, a drawing or a mind map. Stop when you finished with your 10 articles. Sleep on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Tuesday
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🏁 Fill in the gaps
&lt;/h4&gt;

&lt;p&gt;Review your notes and compare with the problem definition. You'll notice some gaps in your notes. Google them again, find 2-3 extra resources and add them to your list. Finish the notes and stop gathering information. Most likely you have already learned just enough to proceed to the next step.&lt;/p&gt;

&lt;h4&gt;
  
  
  👯‍♀️ Show it to a teammate
&lt;/h4&gt;

&lt;p&gt;Now it's time to present your notes to someone else. Explaining the topic to another person will help you understand what you learned.  &lt;/p&gt;

&lt;p&gt;While presenting, reflect the fact that the information is not yet verified. For example, don't say “The best A/B testing tool is X”. Instead, say “I found several authors who really enjoyed X”. Pay extra attention to the remaining unknowns (instead of leaving them out of the discussion).&lt;/p&gt;

&lt;p&gt;Together, narrow down potential solutions to a minimum. For example, if you have five A/B testing services in your notes, pick two most promising based on what you learned so far and on the problem definition. Don't worry that you may occasionally exclude the “right” solution from your shortlist. There is no one right way to solving any technical problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Wednesday, Thursday, Friday
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🏖 Try it in a sandbox
&lt;/h4&gt;

&lt;p&gt;Finally, we are in the famous practice step. I remember times when I was putting together something new that I barely understood only to push it to production faster. This approach was fast at the beginning, but in some cases, it slowed down further development dramatically.&lt;/p&gt;

&lt;p&gt;Before starting to write any code, prepare a list of outstanding questions that you want to clarify through practice. When the problem is small enough, you can start implementing the real solution without properly finishing the investigation. But in the general case, proofs of concepts should not go straight to production to avoid unnecessary risks.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✍️ Write a summary
&lt;/h4&gt;

&lt;p&gt;Finish with a concise report that you wish had been written by someone else before you&lt;br&gt;
started your investigation. Don't put too much effort in it - such reports usually become outdated in 6-9 months. Share the report with the team and agree on the next steps. Switch to something else for a little while to clear your mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise
&lt;/h2&gt;

&lt;p&gt;My quick investigation process includes the following parts: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gathering &amp;amp; structuring information on a very narrow topic (&lt;em&gt;X time&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Sharing with someone else and filtering out (&lt;em&gt;X time&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Building proofs of concept to figure out some crucial details (&lt;em&gt;3X time&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Putting together a summary for discussion and further actions.&lt;/li&gt;
&lt;li&gt;Iterating.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process is very intense because you consume and analyse a lot of new information within a short period of time. It also can be uncomfortable to touch something completely new and to feel stupid after being “an expert” in your field. As Josh Kaufman explained in &lt;a href="https://www.youtube.com/watch?v=5MgBikgcWnY"&gt;“The first 20 hours”&lt;/a&gt; talk, the main barrier to learning something new is emotional. It's often hard to start and even harder to finish. I hope that my article will help you to overcome those issues when you next time will be investigating a new technical problem. &lt;/p&gt;

&lt;p&gt;Remember, you are great!&lt;/p&gt;

</description>
      <category>career</category>
      <category>softskills</category>
      <category>productivity</category>
      <category>techlead</category>
    </item>
    <item>
      <title>The Tech Lead rule: Management first, coding second</title>
      <dc:creator>Kate</dc:creator>
      <pubDate>Sun, 05 Apr 2020 14:36:56 +0000</pubDate>
      <link>https://forem.com/kalabro/the-tech-lead-rule-management-first-coding-second-1k4f</link>
      <guid>https://forem.com/kalabro/the-tech-lead-rule-management-first-coding-second-1k4f</guid>
      <description>&lt;p&gt;I opened my previous post &lt;a href="https://dev.to/kalabro/why-1-1-meetings-are-so-valuable-for-tech-leads-oi8"&gt;about 1:1 meetings&lt;/a&gt; with the following paragraph: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every new Tech Lead will struggle to find time for coding in their busy day. That's very normal because when you step into Tech Lead shoes you suddenly need to learn all those management tools from planning and prioritisation to decision making to conflict solving. &lt;br&gt;
You never know what you will need first, so you will have a fun time learning a bit of everything in parallel (and trying to meet your coding hours quota at the same time). &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I now realised that the idea of that paragraph is not very obvious, especially if you are just about to start as a Tech Lead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Lead is a manager
&lt;/h2&gt;

&lt;p&gt;It seems to be clear that we, Tech Leads, are developers, and we should write some code, should stay current and keep our hard skills sharp. &lt;/p&gt;

&lt;p&gt;What is often forgotten or put at lower priority is that a Tech Lead is a manager and our management skills are the key to our success in the role.&lt;/p&gt;

&lt;p&gt;It's true that as Tech Leads we don't usually have full-time management responsibilities (and often have no authority), but it doesn't change the priority: management first, coding second. &lt;/p&gt;

&lt;p&gt;Even if you've got a very small team and management bit takes just 20% of your time, that 20% is still the most important part of your job. If you deprioritise it or do it poorly, then your small team is in danger: they may miss the deadline, spend time on the wrong task, get stuck or blocked by another team, overengineer the solution, overpromise to the stakeholders, fail at their performance quotas without understanding what they did wrong. Tech Lead as a manager can prevent or notice such issues sooner. Tech Lead as a developer can only try to write the entire codebase alone (and fail at that).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Management first, coding second&lt;/strong&gt; - once you start to see it in this order, it will become clearer what's next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Lead is a developer
&lt;/h2&gt;

&lt;p&gt;Usually, we learn the basics of management by watching how other Tech Leads and managers work. Some of us are good leaders naturally, and it helps too. Still, most of us grow into Tech Leads from Senior Developer role and we don't have a degree in management. Furthermore, you may be affected by a bias that management isn't that important and only creates problems for the dev teams.&lt;/p&gt;

&lt;p&gt;It's important to recognise that &lt;strong&gt;you are now supposed to do a new type of work&lt;/strong&gt;, that you have never done professionally before. It's time for opening your mind for learning and practising new skills. It's not a good time for full-day coding tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Management tasks
&lt;/h2&gt;

&lt;p&gt;Now, when we have the priorities cleared, let's review major areas of your management efforts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📆 Invest in team planning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Help each team member to create a plan for their working week. It doesn't mean that you need to assign tasks to everyone (sometimes you need, but it's an edge case). Your goal is to create and maintain an environment where each team member can figure out what they will be doing tomorrow without checking with you/your manager/stakeholders every day. &lt;/p&gt;

&lt;p&gt;You'll need to have a plan for your week, too, and it should reflect the "management first" rule.&lt;/p&gt;

&lt;p&gt;One common piece of advice to novice Tech Leads is to get better at time management. I think that &lt;strong&gt;you should first get better at mid-term planning (monthly and weekly)&lt;/strong&gt;. Then it will become easier to manage your time within each day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📚Invest in knowledge sharing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure documentation is treated seriously by the team. Lead by example: document things that are often asked by the clients and other team members.&lt;/p&gt;

&lt;p&gt;Make yourself available for questions during the day. If you put yourself in DND mode for an entire day, you won't be able to create an environment where people are willing to help each other. In such an environment,  you'll be able to step back from time to time, and nobody will notice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🌀Invest in workflows and processes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meet your new best friends: company workflows and processes. They are "reusable libraries" of management. They can help many developers stay productive and creative, just like software libraries and frameworks help us build projects quickly and consistently.&lt;/p&gt;

&lt;p&gt;To elaborate further on this metaphor, software libraries should be carefully chosen and maintained by the technical team. The same applies to the workflows and processes in the company. No one software library works for all development projects, and no one workflow fits every software engineering team.&lt;/p&gt;

&lt;p&gt;As a first step, make sure you understand and follow the existing organisational workflows yourself. As an individual contributor, you could sometimes think that they were an unnecessary bureaucracy. As a new Tech Lead, make sure it's not the case, or initiate the change. Workflows should serve the teams, not the other way around. &lt;/p&gt;

&lt;p&gt;Give extra focus to workflows that put you in a gatekeeper position (for example, pull requests can't be deployed without Tech Lead approval). In rare cases, it may be a reasonable requirement, but usually, it indicates a problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👯‍♀️ Regularly check in with your manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So now you keep an eye on the team. Start sharing your observations with your direct manager early, partly to let the problems bubble up. It can be a summary of what went well, what had to be fixed by you, and what requires senior management attention. One of the most important management rules is &lt;strong&gt;"No surprises"&lt;/strong&gt;. If you share the team status regularly, then senior management will be prepared to step in when necessary.&lt;/p&gt;

&lt;p&gt;Funny enough, they may see your problems from various unexpected angles. Be open to that. Sharing your vision helps to align the priorities in both ways. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You:&lt;/em&gt; I have to manually perform project deployments and take database backups. It's not a big deal for me, but I think it can be improved to follow best practices.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Manager:&lt;/em&gt; the project is growing fast, and the dev team should be prepared for frequent and safe deployments. Make DevOps initiative the main priority starting from next week.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You:&lt;/em&gt; I have to manually perform project deployments and take database backups. I think it's a major team blocker (and this is just not a fun job for me).&lt;br&gt;&lt;br&gt;
&lt;em&gt;Manager:&lt;/em&gt; there will be no more deployments for that project starting from next month. It will be replaced with the new development project which should be the main priority starting from next week.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You may say that the manager should have shared the details about the future of your current project sooner. Of course, they would share at some point or they might have already shared it but you missed the point. &lt;/p&gt;

&lt;p&gt;From my practice misalignments happen all the time because everything keeps on changing. Sharing your successes and problems with your manager regularly will help both of you to have "no surprises", or at keep them at a minimum.&lt;/p&gt;

&lt;p&gt;A final note that you should not be focused on problems only, otherwise your manager will start escaping from you. &lt;/p&gt;

&lt;h2&gt;
  
  
  Developer tasks
&lt;/h2&gt;

&lt;p&gt;So, your team know the priorities, help each other when they have questions, and follow workflows to perform common tasks. You manager is aware of some problems that you faced and helps to fix them. Not everything is going so well, but you have a plan in place to improve things in the long run.&lt;/p&gt;

&lt;p&gt;You still feel very busy and unproductive because you spend less time coding and more time planning and communicating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🐌 Reduce your expectations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some organisations &lt;a href="https://github.com/webflow/leadership/blob/master/tech_lead.md#how-much-should-i-expect-to-code"&gt;explicitly set coding expectations&lt;/a&gt; for Tech Lead role. Others don't do that because it may depend on the team and the project at hand.&lt;/p&gt;

&lt;p&gt;In either way, you'll have significantly less time for coding because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You are expected to do some management&lt;/li&gt;
&lt;li&gt;You are not good at management, and you need to learn how to do it well&lt;/li&gt;
&lt;li&gt;You are performing technical oversight and switching context between several different tasks per day&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Accepting this change was very hard for me. It took almost a year for me to understand that investing in my management skills will free up some time for technical tasks in the long term.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🥎 Pick small, not urgent tasks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you include yourself in a sprint as a developer, prefer smaller tasks that don't block other team members. If it's not possible, then prefer pair programming or very close collaboration on a task so that someone else will be able to finish it without you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛩 Block time for coding sessions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a very common recommendation: book a time for coding in DND (Do not disturb / in airplane) mode, and everything will be fine. From my experience, it will indeed, &lt;strong&gt;if you follow all the other recommendations listed above&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I personally enjoy having 3-4hr focus slots at the beginning of the day, but we have our daily standup meetings in the middle of that slot. They immediately kill my focus as we start to discuss different aspects of the project, some problems and blockers that require my attention, and the new surprises that should be communicated up. &lt;/p&gt;

&lt;p&gt;I accept this distraction because I find our daily standups very valuable from the management perspective. I could also skip, postpone or make them asynchronous. As a Tech Lead, when you make choices like this, you have to keep the organisation and the team as your priorities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👏 Take off your Tech Lead hat&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Normal Tech Lead schedule will not allow you to grow as a software developer at the same pace as it used to be. However, your technical expertise is crucial for running a technical team. Yes, you can learn from your teammates while reviewing the code. Yes, you can experiment with the code while you are working on your smaller tech tasks during your focus hours. Yes, you can read some blog posts in your spare time. Yes, you can build a pet project. It's great, but not enough for staying current in the modern IT world. &lt;/p&gt;

&lt;p&gt;Tech Lead role isn't the final career destination for most of us. First of all, it's very challenging because you are a manager and a developer at the same time, and you are kind of okay at both. That's why folks often move on to full management or full development roles from this point. Your Tech Lead experience will help you succeed in either route.&lt;/p&gt;

&lt;p&gt;Some companies periodically rotate Tech Leads in their teams. Others try to spread the management burden across the whole team ("🦄 No-Managers teams"). Finally, you can simply ask your manager to put you on another project for a couple of months. It may be enough to get refreshed and upskilled.&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise
&lt;/h2&gt;

&lt;p&gt;It took me two years to realise that “How to find time to code?” is the wrong question for a Tech Lead. You should focus on getting better at management, and ask your boss to give you “management holidays” if you need to invest more time in your hard skills.&lt;/p&gt;

&lt;p&gt;Tech Lead is a very challenging role, partially because we put a lot of pressure on ourselves and hesitate to ask our senior colleagues for advice. This experience is "unforgettable" as it changes your understanding of software development process. With this new understanding, you can do more either as a developer or as a manager. &lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;

</description>
      <category>career</category>
      <category>softskills</category>
      <category>productivity</category>
      <category>techlead</category>
    </item>
  </channel>
</rss>
